import 'package:flutter/material.dart'; import 'package:pshared/provider/payout_verification.dart'; import 'package:pweb/controllers/common/cooldown.dart'; import 'package:pweb/models/state/flow_status.dart'; class PayoutVerificationController extends ChangeNotifier { PayoutVerificationController() { _cooldown = CooldownController(onTick: () => notifyListeners()); } PayoutVerificationProvider? _provider; FlowStatus _status = FlowStatus.idle; Object? _error; late final CooldownController _cooldown; String? _contextKey; String? _cooldownContextKey; FlowStatus get status => _status; bool get isSubmitting => _status == FlowStatus.submitting; bool get isResending => _status == FlowStatus.resending; bool get hasError => _status == FlowStatus.error; bool get verificationSuccess => _status == FlowStatus.success; Object? get error => _error; String get target => _provider?.target ?? ''; int get cooldownRemainingSeconds => _cooldown.remainingSeconds; bool get isCooldownActive => _cooldown.isActive; bool isCooldownActiveFor(String? contextKey) { if (!_cooldown.isActive) return false; return _cooldownContextKey == contextKey; } int cooldownRemainingSecondsFor(String? contextKey) { if (_cooldownContextKey != contextKey) return 0; return _cooldown.remainingSeconds; } void update(PayoutVerificationProvider provider) { if (identical(_provider, provider)) return; _provider?.removeListener(_onProviderChanged); _provider = provider; _provider?.addListener(_onProviderChanged); _syncCooldown(provider.cooldownUntil); } void setContextKey(String? contextKey) { if (_contextKey == contextKey) return; _contextKey = contextKey; _cooldownContextKey = null; _cooldown.stop(); } Future requestCode() async { final provider = _provider; if (provider == null) { throw StateError('Payout verification provider is not ready'); } _bindCooldownContext(); _error = null; _setStatus(FlowStatus.submitting); try { await provider.requestCode(); _setStatus(FlowStatus.idle); } catch (e) { _error = e; _setStatus(FlowStatus.error); rethrow; } } Future submitCode(String code) async { final provider = _provider; if (provider == null) { throw StateError('Payout verification provider is not ready'); } _error = null; _setStatus(FlowStatus.submitting); try { await provider.confirmCode(code); _setStatus(FlowStatus.success); } catch (e) { _error = e; _setStatus(FlowStatus.error); } } Future resendCode() async { final provider = _provider; if (provider == null) { throw StateError('Payout verification provider is not ready'); } if (isResending || isCooldownActive) return; _bindCooldownContext(); _error = null; _setStatus(FlowStatus.resending); try { await provider.resendCode(); _setStatus(FlowStatus.idle); } catch (e) { _error = e; _setStatus(FlowStatus.error); } } void reset() { _error = null; _setStatus(FlowStatus.idle); _cooldown.stop(); _cooldownContextKey = null; _contextKey = null; _provider?.reset(); } void resetStatus() { _error = null; _setStatus(FlowStatus.idle); } void _onProviderChanged() { _syncCooldown(_provider?.cooldownUntil); notifyListeners(); } void _syncCooldown(DateTime? until) { if (_cooldownContextKey == null || _cooldownContextKey != _contextKey) { _cooldown.stop(notify: _cooldown.isActive); return; } if (until == null) { _cooldown.stop(notify: _cooldown.isActive); return; } if (!_isCooldownActive(until)) { _cooldown.stop(notify: _cooldown.isActive); return; } final currentUntil = _cooldown.until; if (currentUntil == null || !currentUntil.isAtSameMomentAs(until)) { _cooldown.syncUntil(until, notify: true); } } bool _isCooldownActive(DateTime until) => until.isAfter(DateTime.now()); void _bindCooldownContext() { final key = _contextKey; if (key == null) { _cooldownContextKey = null; _cooldown.stop(); return; } if (_cooldownContextKey == key) return; _cooldown.stop(); _cooldownContextKey = key; } void _setStatus(FlowStatus status) { if (_status == status) return; _status = status; notifyListeners(); } @override void dispose() { _provider?.removeListener(_onProviderChanged); _cooldown.dispose(); super.dispose(); } }