import 'dart:async';

import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';

import '../repositories/webrtc_repository.dart';

/// WebRTC 视频连接状态枚举
enum WebrtcConnectionState {
  /// 未连接
  disconnected,

  /// 正在连接
  connecting,

  /// 已连接，视频流播放中
  connected,

  /// 正在重连
  reconnecting,

  /// 连接失败
  failed,
}

/// WebRTC 实时视频服务层
///
/// 职责：
/// - 管理 WebRTC P2P 连接生命周期（初始化、连接、重连、释放）
/// - 管理 [RTCVideoRenderer] 实例，供 UI 层 [RTCVideoView] 渲染
/// - 通过 DataChannel 发送心跳保活
/// - 通过 [_connectionGen] 代际计数器防止快速重连时的竞态
///
/// 涉及页面：首页监护舱 - 监控画面
class WebrtcService {
  final WebrtcRepository _repository;

  /// 视频渲染器（供 RTCVideoView 使用）
  /// 生命周期：[renderer] 在首次 connect 时 initialize，
  /// stop() 只清空 srcObject 不 dispose，保持 PlatformView 存活；
  /// 仅在 [dispose] 最终销毁。
  final RTCVideoRenderer renderer = RTCVideoRenderer();

  /// 渲染器是否已完成首次初始化
  bool _rendererInitialized = false;

  /// P2P 连接实例
  RTCPeerConnection? _peerConnection;

  /// PTZ 控制数据通道
  RTCDataChannel? _dataChannel;

  /// 心跳定时器
  Timer? _heartbeatTimer;

  /// 是否正在重连（防止重复重连）
  bool _isReconnecting = false;

  /// 连接代际计数器 —— 每次发起新连接时 +1，
  /// 用于在信令 HTTP 响应返回后校验当前连接是否已被新连接替代。
  /// 若代际不匹配则丢弃过期响应，防止在新 PeerConnection 上
  /// 错误地 setRemoteDescription 导致 native SIGSEGV。
  int _connectionGen = 0;

  /// 连接状态广播流
  final StreamController<WebrtcConnectionState> _stateController =
      StreamController<WebrtcConnectionState>.broadcast();

  /// 连接状态流（供 UI 层订阅）
  Stream<WebrtcConnectionState> get connectionStateStream =>
      _stateController.stream;

  WebrtcConnectionState _currentState = WebrtcConnectionState.disconnected;

  /// 当前连接状态
  WebrtcConnectionState get currentState => _currentState;

  /// 连接凭据（用于断线重连时重新获取信令 URL）
  String? _deviceNo;
  String? _password;
  String? _lastUrl;

  /// ICE / STUN 服务器配置
  static const _iceServers = {
    'iceServers': [
      {'urls': 'stun:stun.l.google.com:19302'},
    ],
  };

  WebrtcService() : _repository = WebrtcRepository();

  // ==================== 公共接口 ====================

  /// 初始化 WebRTC 连接
  ///
  /// [deviceNo] 设备摄像头序列号（cameraSn）
  /// [password] 设备 WiFi 密码
  Future<void> connect({
    required String deviceNo,
    required String password,
  }) async {
    _deviceNo = deviceNo;
    _password = password;

    _updateState(WebrtcConnectionState.connecting);

    try {
      // 1. 通过 HTTP 获取信令交换 URL
      final result = await _repository.getAddress(
        deviceNo: deviceNo,
        password: password,
      );

      if (result.data == null || result.data!.urlList.isEmpty) {
        debugPrint('[WebrtcService] 获取信令地址失败：URL 列表为空');
        _updateState(WebrtcConnectionState.failed);
        return;
      }

      _lastUrl = result.data!.urlList.first;
      debugPrint('[WebrtcService] 信令地址: $_lastUrl');

      // 2. 初始化 WebRTC P2P 连接
      await _initWebrtc(_lastUrl!);
    } catch (e) {
      debugPrint('[WebrtcService] 连接失败: $e');
      _updateState(WebrtcConnectionState.failed);
    }
  }

  /// 停止当前连接（不关闭 StreamController，不销毁 Renderer）
  ///
  /// 用于模式切换场景：停掉 WebRTC 连接资源（PeerConnection、DataChannel、
  /// 媒体轨道），但保持 StreamController 存活（后续 connect 可继续广播状态）
  /// 且保持 Renderer 存活（RTCVideoView 的 PlatformView 不会访问已销毁纹理）。
  Future<void> stop() async {
    debugPrint('[WebrtcService] 停止连接...');

    _heartbeatTimer?.cancel();
    _heartbeatTimer = null;

    await _dataChannel?.close();
    _dataChannel = null;

    // 停止所有音视频轨道，并清空 srcObject 使 RTCVideoView 显示黑屏
    renderer.srcObject?.getAudioTracks().forEach((t) => t.stop());
    renderer.srcObject?.getVideoTracks().forEach((t) => t.stop());
    renderer.srcObject = null;

    await _peerConnection?.close();
    await _peerConnection?.dispose();
    _peerConnection = null;

    _updateState(WebrtcConnectionState.disconnected);
  }

  /// 释放所有资源（含 Renderer + StreamController）
  ///
  /// 调用后此实例不可再复用 [connect]。
  Future<void> dispose() async {
    debugPrint('[WebrtcService] 释放资源...');
    await stop();
    await renderer.dispose();
    _rendererInitialized = false;
    await _stateController.close();
  }

  // ==================== 内部实现 ====================

  /// 初始化 WebRTC 连接核心逻辑
  ///
  /// 每次调用会递增 [_connectionGen]，用于信令响应返回后校验代际。
  Future<void> _initWebrtc(String url) async {
    // 递增代际，捕获当前值用于后续校验
    final currentGen = ++_connectionGen;
    debugPrint('[WebrtcService] _initWebrtc gen=$currentGen');

    // 清理上一次连接的残留，防止 PC 泄漏
    // 和后续 onConnectionState 迟到触发重连
    await _cleanupConnection();

    // 仅首次需要初始化渲染器；stop() 后 renderer 保持存活无需重新初始化
    if (!_rendererInitialized) {
      await renderer.initialize();
      _rendererInitialized = true;
    }

    // 创建 P2P 连接
    _peerConnection = await createPeerConnection(_iceServers);

    // 首帧渲染完成信号 —— 视频真正可播放时触发
    final frameCompleter = Completer<void>();
    renderer.onResize = () {
      if (!frameCompleter.isCompleted) {
        frameCompleter.complete();
      }
    };

    // 监听远程视频轨道
    _peerConnection!.onTrack = (RTCTrackEvent event) {
      if (event.track.kind == 'video' && event.streams.isNotEmpty) {
        debugPrint('[WebrtcService] 收到远程视频轨道');
        renderer.srcObject = event.streams.first;
      }
    };

    // 监听连接状态变化 —— 断线时自动重连
    _peerConnection!.onConnectionState = (RTCPeerConnectionState state) {
      debugPrint('[WebrtcService] P2P 连接状态: $state');
      if (state == RTCPeerConnectionState.RTCPeerConnectionStateDisconnected ||
          state == RTCPeerConnectionState.RTCPeerConnectionStateFailed) {
        _onReconnect();
      }
    };

    // 添加视频收发器（仅接收，不发送）
    await _peerConnection!.addTransceiver(
      kind: RTCRtpMediaType.RTCRtpMediaTypeVideo,
      init: RTCRtpTransceiverInit(direction: TransceiverDirection.RecvOnly),
    );

    // 创建数据通道（PTZ 控制指令 + 心跳）
    _dataChannel = await _peerConnection!.createDataChannel(
      'ptz-control',
      RTCDataChannelInit()
        ..ordered = true
        ..protocol = 'sctp',
    );

    _dataChannel!.onDataChannelState = (RTCDataChannelState state) {
      debugPrint('[WebrtcService] DataChannel 状态: $state');
      if (state == RTCDataChannelState.RTCDataChannelOpen) {
        _startHeartbeat();
      } else {
        _heartbeatTimer?.cancel();
      }
    };

    // 创建 SDP Offer 并设为本地描述
    final offer = await _peerConnection!.createOffer({
      'offerToReceiveAudio': 1,
    });

    await _peerConnection!.setLocalDescription(offer);
    debugPrint('[WebrtcService] 本地 SDP 已设置，发送 Offer...');

    // 通过 HTTP 发送 SDP Offer 到信令服务器，获取 SDP Answer
    // 注意：使用裸 Dio 实例，因为信令 URL 是完整地址而非基于 baseUrl 的相对路径
    final response = await Dio().post(
      url,
      data: offer.sdp,
      options: Options(
        headers: {'Content-Type': 'text/plain'},
        contentType: 'text/plain',
        responseType: ResponseType.json,
      ),
    );

    // ========== 竞态防护 ==========
    if (currentGen != _connectionGen) {
      debugPrint(
        '[WebrtcService] 代际不匹配 (current=$currentGen, latest=$_connectionGen)，'
        '丢弃过期响应',
      );
      return;
    }

    // 设置远端 SDP Answer
    await _peerConnection!.setRemoteDescription(
      RTCSessionDescription(response.data['sdp'], 'answer'),
    );
    debugPrint('[WebrtcService] 远端 SDP 已设置，等待视频流...');

    // 等待首帧渲染（真正可播放时才算连接完成），带超时保护
    await frameCompleter.future.timeout(
      const Duration(milliseconds: 3000),
      onTimeout: () => debugPrint('[WebrtcService] 首帧渲染超时（3s）'),
    );
    renderer.onResize = null;

    _updateState(WebrtcConnectionState.connected);
    debugPrint('[WebrtcService] WebRTC 连接建立完成');
  }

  /// 清理上一次连接残留（PC + DataChannel + 心跳）
  Future<void> _cleanupConnection() async {
    _heartbeatTimer?.cancel();
    _heartbeatTimer = null;

    if (_dataChannel != null) {
      await _dataChannel!.close();
      _dataChannel = null;
    }

    if (_peerConnection != null) {
      await _peerConnection!.close();
      await _peerConnection!.dispose();
      _peerConnection = null;
    }
  }

  /// 断线重连
  Future<void> _onReconnect() async {
    if (_isReconnecting) return;
    _isReconnecting = true;

    debugPrint('[WebrtcService] 开始重连...');
    _updateState(WebrtcConnectionState.reconnecting);

    try {
      // 清理当前连接
      await _cleanupConnection();

      // 重新获取信令 URL（地址可能已过期）
      if (_deviceNo != null && _password != null) {
        final result = await _repository.getAddress(
          deviceNo: _deviceNo!,
          password: _password!,
        );
        if (result.data != null && result.data!.urlList.isNotEmpty) {
          _lastUrl = result.data!.urlList.first;
        }
      }

      if (_lastUrl == null) {
        debugPrint('[WebrtcService] 重连失败：无可用的信令 URL');
        _updateState(WebrtcConnectionState.failed);
        return;
      }

      // 重新初始化连接
      await _initWebrtc(_lastUrl!);
    } catch (e) {
      debugPrint('[WebrtcService] 重连异常: $e');
      _updateState(WebrtcConnectionState.failed);
    } finally {
      _isReconnecting = false;
    }
  }

  /// DataChannel 心跳保活
  ///
  /// 每 5 秒发送一次设备活跃心跳指令，
  /// 防止服务端因超时断开 DataChannel。
  void _startHeartbeat() {
    _heartbeatTimer?.cancel();
    _heartbeatTimer = Timer.periodic(const Duration(seconds: 5), (timer) {
      if (_dataChannel == null) return;
      _dataChannel!.send(
        RTCDataChannelMessage(
          'trans_cmd_string.cgi?cmd=2131&command=1&DevActiveTime=10&',
        ),
      );
    });
  }

  /// 更新连接状态并广播给订阅者
  void _updateState(WebrtcConnectionState state) {
    if (_currentState == state) return;
    _currentState = state;
    if (!_stateController.isClosed) {
      _stateController.add(state);
    }
  }
}
