import 'dart:async';


import 'package:networks_sdk/networks_sdk.dart';

import 'network_backoff_debouncer.dart';

/// 消息预处理回调
///
/// 参考 HTTP 层 onTokenRefresh 的回调注入模式。
/// App 层在 Provider 装配时注入解密/解析逻辑，
/// 不在 SDK 内部调用加解密 SDK。
typedef MessageTransformer = Map<String, dynamic> Function(
  Map<String, dynamic> raw,
);

/// WebSocket 连接管理
///
/// 在 SocketClient（SDK 底层能力）之上封装：
/// - 连接/断连生命周期（登录连接、登出断连）
/// - 前后台生命周期（后台断连省电、前台自动重连）
/// - 网络状态响应（断网断连、恢复网络立即重连）
/// - 操作前置检查（网络可用性 + 后台状态）
/// - 消息预处理管道（通过 [onMessageTransform] 回调注入解密等）
/// - 发送 API 透传
///
/// 不使用单例，通过 Riverpod Provider 注入。
///
/// ## 数据流位置
///
/// ```
/// SocketClient.messageStream（原始消息）
///   → onMessageTransform?（解密回调，App 层注入）
///     → ★ SocketManager.messageStream ★   ← 你在这里
///       → 业务模块消费
/// ```
///
/// ## 生命周期流程
///
/// ```
/// 登录成功 → connect(token) → 前置检查 → 建立连接
/// App 进后台 → onEnterBackground() → 断开连接（省电）
/// App 回前台 → onEnterForeground() → 检查网络 → 自动重连
/// 网络丢失 → handleNetworkLost() → 断开连接
/// 网络恢复 → handleNetworkRestored() → 退避重连（防抖动）
/// 登出 → disconnect() → 断开连接，清除 token
/// ```
///
/// ## 前置检查策略
///
/// 所有会发起网络操作的方法都先检查前置条件：
/// - connect → 检查网络可用性 + 是否在后台
/// - send / sendString → 检查连接状态 + 是否在后台
/// - onEnterForeground 重连 → 检查网络可用性
class SocketManager {
  final NetworksMessagingApi _client;
  final String _wsUrl;

  /// 消息预处理回调
  ///
  /// 登录后由 Provider 层注入，用于消息解密等。
  /// 不注入时直接透传原始消息。
  ///
  /// TODO: 接入加解密 SDK 后实现
  final MessageTransformer? onMessageTransform;

  /// 网络可用性查询（App 层注入）
  ///
  /// 与 HTTP 层 [ApiConfig.onCheckNetworkAvailable] 对称。
  /// 连接和重连前调用，无网络时跳过操作并标记恢复时重试。
  final Future<bool> Function()? onCheckNetworkAvailable;

  /// 日志回调
  final void Function(String message, {String? tag})? onLog;

  // ── 内部状态 ──

  /// 上次连接使用的 token，用于前台/网络恢复时自动重连
  String? _lastToken;

  /// 后台断连标记：前台恢复时需要重连
  bool _reconnectOnForeground = false;

  /// 断网标记：网络恢复时需要重连
  bool _reconnectOnNetworkRestore = false;

  /// 当前是否在后台
  bool _isInBackground = false;

  /// 网络恢复退避防抖器
  ///
  /// 网络抖动（快速 offline → online 切换）时，
  /// 用指数退避避免反复锤服务器。
  /// 通过 [NetworkBackoffDebouncer] 实现指数退避。
  final NetworkBackoffDebouncer _networkDebouncer = NetworkBackoffDebouncer();

  /// 前台恢复延迟重连定时器
  ///
  /// 回前台后延迟 500ms 等待网络稳定再重连。
  /// 期间如果再次进后台 / 主动断连 / dispose，及时取消。
  Timer? _foregroundReconnectTimer;

  SocketManager({
    required NetworksMessagingApi client,
    required String wsUrl,
    this.onMessageTransform,
    this.onCheckNetworkAvailable,
    this.onLog,
  })  : _client = client,
        _wsUrl = wsUrl;

  // ── 连接 ──────────────────────────────────────────────────────────────────

  /// 连接 WebSocket
  ///
  /// 登录成功后调用，token 从登录响应获取。
  /// URL 由 Provider 层从 AppConfig 构建后注入，此处不关心来源。
  ///
  /// 前置检查：
  /// - 在后台 → 跳过，标记前台恢复时重连
  /// - 无网络 → 跳过，标记网络恢复时重连
  Future<bool> connect({required String token}) async {
    _lastToken = token;
    _reconnectOnForeground = false;
    _reconnectOnNetworkRestore = false;

    // 前置检查：在后台不连接（省电）
    if (_isInBackground) {
      _reconnectOnForeground = true;
      _log('In background, defer connect to foreground');
      return false;
    }

    // 前置检查：无网络不连接
    if (!await _isNetworkAvailable()) {
      _reconnectOnNetworkRestore = true;
      _log('No network, defer connect to network restore');
      return false;
    }

    _log('Connecting...');
    return _client.connect(_wsUrl, token: token);
  }

  /// 断开连接（主动断连）
  ///
  /// 登出时调用。清除 token，取消所有待执行的重连，不再自动重连。
  Future<void> disconnect() async {
    _lastToken = null;
    _reconnectOnForeground = false;
    _reconnectOnNetworkRestore = false;
    _foregroundReconnectTimer?.cancel();
    _foregroundReconnectTimer = null;
    _networkDebouncer.cancel();
    _log('Disconnecting (manual)');
    await _client.disconnect();
  }

  /// 当前是否已连接
  bool get isConnected => _client.isConnected;

  /// 当前连接状态
  SocketConnectionState get connectionState => _client.connectionState;

  /// 当前是否在后台
  bool get isInBackground => _isInBackground;

  // ── 前后台生命周期 ────────────────────────────────────────────────────────
  //
  //   后台 → 断连（省电省流量）
  //   前台 → 自动重连（如果之前有连接）

  /// App 进后台 → 断开连接，标记前台恢复时重连
  ///
  /// 由 App 层 WidgetsBindingObserver 在 [AppLifecycleState.paused] 时调用。
  /// 后台保持连接会消耗电量和流量，断开后由 push 通知兜底。
  void onEnterBackground() {
    _isInBackground = true;
    // 取消待执行的前台重连（防止快速 前台→后台 切换导致后台建连）
    _foregroundReconnectTimer?.cancel();
    _foregroundReconnectTimer = null;
    // 同步 SocketClient 内部状态（与 onEnterForeground 对称）
    _client.onEnterBackground();

    if (_lastToken == null) return; // 未登录，无需处理

    // 与 _handleNetworkLost 保持一致：
    // 不仅 connected，connecting / reconnecting 也要断开，
    // 防止 SocketClient 在后台继续尝试连接浪费电量和流量。
    if (_client.isConnected ||
        _client.connectionState == SocketConnectionState.connecting ||
        _client.connectionState == SocketConnectionState.reconnecting) {
      _reconnectOnForeground = true;
      _log('Entering background, disconnecting to save battery');
      _client.disconnect();
    }
  }

  /// App 回前台 → 自动重连（如果之前后台断连）
  ///
  /// 由 App 层 WidgetsBindingObserver 在 [AppLifecycleState.resumed] 时调用。
  /// 重连前检查网络可用性，无网络时延迟到网络恢复事件再连。
  void onEnterForeground() {
    _isInBackground = false;
    _client.onEnterForeground();

    if (_reconnectOnForeground && _lastToken != null) {
      _reconnectOnForeground = false;
      _log('Returning to foreground, reconnecting...');
      // 延迟 500ms 等待网络稳定，通过 Timer 跟踪以便进后台时取消
      _foregroundReconnectTimer?.cancel();
      _foregroundReconnectTimer = Timer(
        const Duration(milliseconds: 500),
        () async {
          _foregroundReconnectTimer = null;
          // 双重保险：回调执行时再次检查后台状态
          if (_isInBackground) {
            _reconnectOnForeground = true;
            _log('Went back to background during delay, skip reconnect');
            return;
          }
          if (!_client.isConnected && _lastToken != null) {
            // 前置检查：网络可用性
            if (!await _isNetworkAvailable()) {
              _reconnectOnNetworkRestore = true;
              _log('Network unavailable, defer reconnect to network restore');
              return;
            }
            _client.connect(_wsUrl, token: _lastToken!);
          }
        },
      );
    }
  }

  // ── 网络状态变化 ──────────────────────────────────────────────────────────
  //
  //   网络丢失 → 断连（避免无效重试消耗资源）
  //   网络恢复 → 退避重连（防网络抖动）

  /// 网络状态变化处理
  ///
  /// 由 App 层 NetworkMonitor.onStatusChanged 事件驱动。
  void handleNetworkStatusChanged({required bool isAvailable}) {
    if (isAvailable) {
      _handleNetworkRestored();
    } else {
      _handleNetworkLost();
    }
  }

  /// 网络丢失 → 断开连接，标记网络恢复时重连
  ///
  /// 断网后继续重试没有意义，主动断连避免无效重连消耗资源。
  void _handleNetworkLost() {
    if (_lastToken == null) return; // 未登录，无需处理

    if (_client.isConnected ||
        _client.connectionState == SocketConnectionState.connecting ||
        _client.connectionState == SocketConnectionState.reconnecting) {
      _reconnectOnNetworkRestore = true;
      _log('Network lost, disconnecting');
      _client.disconnect();
    }
  }

  /// 网络恢复 → 退避重连
  ///
  /// 通过 [NetworkBackoffDebouncer] 控制重连频率，
  /// 网络抖动（快速 offline/online 切换）时不会反复锤服务器。
  ///
  /// 退避进程：4s → 8s → 16s → 32s → 60s（封顶），
  /// 网络稳定超过 2 分钟后重置。
  void _handleNetworkRestored() {
    if (_reconnectOnNetworkRestore && _lastToken != null) {
      _reconnectOnNetworkRestore = false;

      // 在后台不重连，等前台恢复时再连
      if (_isInBackground) {
        _reconnectOnForeground = true;
        _log('Network restored but in background, defer to foreground');
        return;
      }

      _log('Network restored, scheduling reconnect with backoff');
      _networkDebouncer.call(() {
        if (!_client.isConnected && _lastToken != null && !_isInBackground) {
          _log('Backoff timer fired, reconnecting');
          _client.connect(_wsUrl, token: _lastToken!);
        }
      });
    }
  }

  // ── 消息流 ────────────────────────────────────────────────────────────────

  /// 处理后的 JSON 消息流
  ///
  /// 经过 [onMessageTransform] 预处理（解密等）后的消息。
  /// 业务模块应监听此流，不直接监听 SocketClient.messageStream。
  Stream<Map<String, dynamic>> get messageStream {
    if (onMessageTransform != null) {
      return _client.messageStream.map(onMessageTransform!);
    }
    return _client.messageStream;
  }

  /// 原始消息流（不经预处理，调试用）
  Stream<String> get rawMessageStream => _client.rawMessageStream;

  /// 连接状态变化流
  Stream<SocketConnectionState> get connectionStateStream =>
      _client.connectionStateStream;

  /// 错误流
  Stream<SocketError> get errorStream => _client.errorStream;

  // ── 发送 ──────────────────────────────────────────────────────────────────

  /// 发送 JSON 消息
  ///
  /// 前置检查：未连接或在后台时不发送。
  Future<bool> send(Map<String, dynamic> message) {
    if (!_canSend()) return Future.value(false);
    return _client.send(message);
  }

  /// 发送原始字符串
  ///
  /// 前置检查：未连接或在后台时不发送。
  Future<bool> sendString(String message) {
    if (!_canSend()) return Future.value(false);
    return _client.sendString(message);
  }

  // ── 释放 ──────────────────────────────────────────────────────────────────

  /// 释放所有资源
  Future<void> dispose() {
    _foregroundReconnectTimer?.cancel();
    _foregroundReconnectTimer = null;
    _networkDebouncer.dispose();
    return _client.dispose();
  }

  // ── 内部 ──────────────────────────────────────────────────────────────────

  /// 发送前置检查
  ///
  /// 两重保险：连接状态 + 后台状态。
  /// 后台已断连所以 isConnected 通常就能拦住，
  /// 但显式检查 _isInBackground 防止边界情况遗漏。
  bool _canSend() {
    if (!_client.isConnected) {
      _log('Not connected, cannot send');
      return false;
    }
    if (_isInBackground) {
      _log('In background, skip send');
      return false;
    }
    return true;
  }

  /// 查询网络可用性
  ///
  /// 未注入回调时默认网络可用（不阻塞操作）。
  Future<bool> _isNetworkAvailable() async {
    if (onCheckNetworkAvailable == null) return true;
    return onCheckNetworkAvailable!();
  }

  void _log(String message) {
    onLog?.call(message, tag: 'SocketManager');
  }
}
