import 'dart:async';
import 'dart:math';

/// 网络恢复退避防抖器
///
/// 网络状态频繁切换（WiFi 不稳定、隧道信号间断等）时，
/// 避免每次恢复都立即重连，用指数退避控制重连频率。
///
/// 增加 jitter 防止多设备同时重连的群体效应（thundering herd）。
///
/// ## 退避策略
///
/// - 首次触发 → 等 baseDelay 后执行
/// - 短时间内再次触发 → 延迟翻倍（指数退避）
/// - 长时间静默后触发 → 重置为 baseDelay（网络已稳定）
///
/// ## 退避进程（默认参数）
///
/// ```
/// 触发 1 → 4s 后执行
/// 触发 2 → 8s 后执行
/// 触发 3 → 16s 后执行
/// 触发 4 → 32s 后执行
/// 触发 5 → 60s（封顶）
/// ...静默超过 2 分钟...
/// 触发 N → 4s（重置）
/// ```
///
/// ## 使用
///
/// ```dart
/// final debouncer = NetworkBackoffDebouncer();
///
/// // 网络恢复事件
/// debouncer.call(() {
///   socketManager.reconnect();
/// });
/// ```
class NetworkBackoffDebouncer {
  /// 初始延迟
  final Duration baseDelay;

  /// 退避上限
  final Duration maxDelay;

  /// 静默多久后重置为初始延迟（网络已稳定，不再退避）
  final Duration resetThreshold;

  /// 退避倍数
  final double factor;

  Duration _currentDelay;
  DateTime? _lastTriggerTime;
  Timer? _timer;
  final _random = Random();

  NetworkBackoffDebouncer({
    this.baseDelay = const Duration(seconds: 4),
    this.maxDelay = const Duration(seconds: 60),
    this.resetThreshold = const Duration(minutes: 2),
    this.factor = 2.0,
  }) : _currentDelay = baseDelay;

  /// 触发退避执行
  ///
  /// 取消上一个待执行的 action，按当前退避延迟重新计时。
  /// 短时间内多次触发只执行最后一次，延迟逐步递增。
  void call(void Function() action) {
    final now = DateTime.now();

    if (_lastTriggerTime == null ||
        now.difference(_lastTriggerTime!) > resetThreshold) {
      // 首次触发 or 长时间静默 → 重置
      _currentDelay = baseDelay;
    } else {
      // 短时间内再次触发 → 退避
      final nextMs = (_currentDelay.inMilliseconds * factor).toInt();
      _currentDelay = Duration(
        milliseconds: nextMs < maxDelay.inMilliseconds
            ? nextMs
            : maxDelay.inMilliseconds,
      );
    }

    _lastTriggerTime = now;

    // 加 jitter（+0~25%），防止多设备同时重连
    final jitterMs = _random.nextInt((_currentDelay.inMilliseconds * 0.25).toInt().clamp(1, 15000));
    final delayWithJitter = _currentDelay + Duration(milliseconds: jitterMs);

    _timer?.cancel();
    _timer = Timer(delayWithJitter, action);
  }

  /// 取消待执行的 action
  void cancel() {
    _timer?.cancel();
    _timer = null;
  }

  /// 释放资源
  void dispose() {
    cancel();
  }
}
