import 'dart:async';


class CooldownController {
  CooldownController({void Function()? onTick}) : _onTick = onTick;

  final void Function()? _onTick;
  Timer? _timer;
  DateTime? _until;
  int _remainingSeconds = 0;

  int get remainingSeconds => _remainingSeconds;
  bool get isActive => _remainingSeconds > 0;
  DateTime? get until => _until;

  void start(Duration duration) {
    startUntil(DateTime.now().add(duration));
  }

  void startUntil(DateTime until) {
    _until = until;
    _restartTimer();
    _syncRemaining(notify: true);
  }

  void syncUntil(DateTime? until, {bool notify = true}) {
    if (until == null) {
      stop(notify: notify);
      return;
    }
    _until = until;
    _restartTimer();
    _syncRemaining(notify: notify);
  }

  void stop({bool notify = false}) {
    _timer?.cancel();
    _timer = null;
    _until = null;
    final hadRemaining = _remainingSeconds != 0;
    _remainingSeconds = 0;
    if (notify && hadRemaining) {
      _onTick?.call();
    }
  }

  void dispose() {
    _timer?.cancel();
    _timer = null;
  }

  void _restartTimer() {
    _timer?.cancel();
    _timer = null;
    if (_remaining() <= 0) return;

    _timer = Timer.periodic(const Duration(seconds: 1), (_) {
      final nextRemaining = _remaining();
      if (nextRemaining <= 0) {
        stop(notify: true);
        return;
      }
      if (nextRemaining != _remainingSeconds) {
        _remainingSeconds = nextRemaining;
        _onTick?.call();
      }
    });
  }

  void _syncRemaining({required bool notify}) {
    final nextRemaining = _remaining();
    if (nextRemaining == _remainingSeconds) return;
    _remainingSeconds = nextRemaining;
    if (notify) {
      _onTick?.call();
    }
  }

  int _remaining() {
    final until = _until;
    if (until == null) return 0;
    final remaining = until.difference(DateTime.now()).inSeconds;
    return remaining < 0 ? 0 : remaining;
  }
}
