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

import 'self_codec_decoder.dart';

import '../config/ice_servers.dart';
import '../models/signal_message.dart';
import '../proto/control_message.pb.dart';
import '../signaling/signaling_client.dart';
import '../utils/control_commands.dart';

/// WebRTC 全托管模式下，由原生 VideoSink 探针逐帧实测得到的解码耗时统计。
class _DecodeProbeStats {
  final double lastMs;
  final double avgMs;
  final double peakMs;
  final int totalFrames;
  final int fpsNow;
  final int fpsAvg;
  const _DecodeProbeStats({
    required this.lastMs,
    required this.avgMs,
    required this.peakMs,
    required this.totalFrames,
    required this.fpsNow,
    required this.fpsAvg,
  });
}

/// 封装 WebRTC 连接逻辑（对应 Android 端 WebRtcClient）。
///
/// 职责：
/// - 创建 PeerConnection（recvonly 视频 + 控制用 DataChannel）
/// - 创建 Offer 并通过信令发送
/// - 处理 Answer / ICE 候选
/// - 通过 DataChannel 发送控制指令（触摸/滑动/按键）
/// - 采集并解析连接统计信息
///
/// 本类同时兼容 Android 与 iOS（基于 flutter_webrtc）。
class WebRtcController {
  final SignalingClient signaling;
  final String deviceId;
  final String targetDeviceId;
  final String? authType;
  final String? authValue;

  RTCPeerConnection? _pc;
  RTCDataChannel? _dataChannel;
  RTCDataChannel? _videoDataChannel;
  SelfCodecDecoder? _selfCodecDecoder;
  int _currentStreamMode = streamModeWebRtc;
  bool _creatingDecoder = false;

  /// 远端视频渲染器，由调用方持有并显示。
  final RTCVideoRenderer renderer = RTCVideoRenderer();

  void Function()? onConnectionEstablished;
  void Function(String error)? onConnectionFailed;
  void Function()? onDisconnected;

  /// ICE 连接断开（如网络中断、被控端退出），用于提示用户并返回连接设置。
  void Function(String message)? onIceDisconnected;

  /// 远端视频流就绪（renderer 已绑定视频轨道）。
  void Function(RTCVideoRenderer renderer)? onRemoteStream;

  /// 自编码解码纹理已就绪（textureId >= 0）。
  void Function(int)? onSelfCodecReady;

  /// 自编码解码器已释放（连接断开时）。
  void Function()? onSelfCodecLost;

  /// 被控端上报当前生效的串流模式。
  void Function(int mode)? onStreamModeReport;

  /// 被控端上报分辨率（自编码解码器输出尺寸变化时也会触发）。
  void Function(int width, int height)? onResolutionReported;

  /// 被控端上报当前采集帧率与支持的帧率档位（仅 REPORT_RESOLUTION 触发）。
  void Function(int width, int height, int fps, List<int> supportedFps)?
      onFpsReport;

  /// 当前平台（Windows / Linux / Web / iOS 等）不支持原生硬解时回调。
  void Function()? onSelfCodecNotSupported;

  static const String kVideoChannelLabel = 'video_channel';
  static const int streamModeWebRtc = 0;
  static const int streamModeSelfCodec = 1;

  WebRtcController({
    required this.signaling,
    required this.deviceId,
    required this.targetDeviceId,
    this.authType,
    this.authValue,
  });

  /// 初始化渲染器、PeerConnection，并创建 Offer。
  Future<void> initialize() async {
    await renderer.initialize();

    final configuration = {
      'iceServers': kIceServers,
      'sdpSemantics': 'unified-plan',
      'iceCandidatePoolSize': 10,
      // 增强复杂网络下的稳定性，参考 Android 端配置。
      'continualGatheringPolicy': 'gatherContinually',
      'iceTransportsType': 'all',
      'tcpCandidatePolicy': 'enabled',
    };

    final iceUrls = (kIceServers)
        .map((e) => '${e['username'] != null ? '(${e['username']})' : ''}${e['urls']}')
        .join(', ');
    debugPrint('[WebRtcController] signaling server: ${signaling.serverUrl} | '
        'deviceId=$deviceId target=$targetDeviceId');
    debugPrint('[WebRtcController] ICE servers: $iceUrls');

    _pc = await createPeerConnection(configuration);

    _pc!.onIceCandidate = _onIceCandidate;
    _pc!.onIceConnectionState = _onIceConnectionState;
    _pc!.onIceGatheringState = (state) {
      debugPrint('[WebRtcController] ICE gathering state: $state');
    };
    _pc!.onTrack = _onTrack;
    _pc!.onDataChannel = _onDataChannel;

    // 仅接收远端视频（recvonly）。
    await _pc!.addTransceiver(
      kind: RTCRtpMediaType.RTCRtpMediaTypeVideo,
      init: RTCRtpTransceiverInit(direction: TransceiverDirection.RecvOnly),
    );

    // 创建控制用 DataChannel。
    // 使用非可靠、无序模式以降低延迟，解决“不跟手”问题。
    final dcInit = RTCDataChannelInit()
      ..ordered = false
      ..maxRetransmits = 0;
    _dataChannel = await _pc!.createDataChannel(kDataChannelLabel, dcInit);
    _setupDataChannel(_dataChannel!);

    // 创建自编码视频透传通道（无序、不可靠，类似 RTP，最低延迟）。
    // 被控端仅在收到 SET_STREAM_MODE=自编码 后才经此通道推送 H.264 裸流。
    final videoInit = RTCDataChannelInit()
      ..ordered = false
      ..maxRetransmits = 0;
    _videoDataChannel = await _pc!.createDataChannel(
      kVideoChannelLabel,
      videoInit,
    );
    _setupVideoDataChannel(_videoDataChannel!);

    // 创建并发送 Offer。
    final constraints = {
      'mandatory': {
        'OfferToReceiveVideo': true,
        'OfferToReceiveAudio': false,
      },
      'optional': [],
    };
    final offer = await _pc!.createOffer(constraints);
    // 与 WebRTCControlled 的 optimizeSdp 保持一致：Offer 的 m=video 行优先 VP8/VP9，
    // H264 兜底，确保各控制端（桌面/浏览器/Chromium/Linux）都能稳定解码，
    // 即编码端（被控端）与解码端（控制端）协商出一致的、可解码的视频格式。
    final reorderedSdp = _preferVideoCodecs(offer.sdp!);
    final offerWithPref = RTCSessionDescription(reorderedSdp, offer.type);
    await _pc!.setLocalDescription(offerWithPref);
    _sendOffer(reorderedSdp, authType: authType, authValue: authValue);
  }

  /// 重排 Offer SDP 中 `m=video` 行的视频编解码器顺序：VP8/VP9 优先，H264 兜底。
  ///
  /// 与 Android 被控端 [WebRtcClient.optimizeSdp] 的编解码优先级保持一致，
  /// 保证协商出的编码格式控制端一定可解码（编码/解码一致性）。
  String _preferVideoCodecs(String sdp) {
    final lines = sdp.split('\r\n');
    final vp8 = <String>[];
    final vp9 = <String>[];
    final h264 = <String>[];
    for (final line in lines) {
      final t = line.trim();
      if (t.startsWith('a=rtpmap:')) {
        final payload = t.split(':')[1].split(' ')[0];
        if (t.contains('VP8/90000')) {
          vp8.add(payload);
        } else if (t.contains('VP9/90000')) {
          vp9.add(payload);
        } else if (t.contains('H264/90000')) {
          h264.add(payload);
        }
      }
    }
    final ordered = <String>[...vp8, ...vp9, ...h264];
    if (ordered.isEmpty) return sdp;

    final result = <String>[];
    for (final line in lines) {
      final t = line.trim();
      if (t.startsWith('m=video')) {
        final parts = t.split(' ');
        if (parts.length > 3) {
          final head = '${parts[0]} ${parts[1]} ${parts[2]}';
          final rest = parts
              .skip(3)
              .where((p) => !ordered.contains(p))
              .toList();
          result.add([head, ...ordered, ...rest].join(' '));
          continue;
        }
      }
      result.add(line);
    }
    return result.join('\r\n');
  }

  void _onTrack(RTCTrackEvent event) {
    if (event.track.kind != 'video') return;
    _bindRemoteVideo(event);
  }

  /// 绑定远端视频轨道到渲染器。
  ///
  /// 与 Web 端 WebRtcController.ontrack 的兜底逻辑保持一致：
  /// 某些平台/协商场景下（Unified Plan + recvonly）`event.streams` 可能为空，
  /// 此时必须用 `event.track` 自行构造 MediaStream，否则 renderer.srcObject
  /// 为空 -> 控制端拿不到画面（黑屏/一直显示“等待画面”），但控制通道不受影响。
  Future<void> _bindRemoteVideo(RTCTrackEvent event) async {
    MediaStream stream;
    if (event.streams.isNotEmpty) {
      stream = event.streams[0];
    } else {
      // event.streams 为空：用 track 自行构造 MediaStream。
      stream = await createLocalMediaStream('remoteVideo');
      await stream.addTrack(event.track);
    }
    renderer.srcObject = stream;
    onRemoteStream?.call(renderer);
    // 仅在 WebRTC 全托管模式 attach 解码耗时探针（自编码模式用自己的解码器统计）。
    if (_selfCodecDecoder == null) {
      final trackId = event.track.id;
      if (trackId != null) _attachWebRtcDecodeProbe(trackId);
    }
  }

  /// 解码耗时探针通道（原生侧给远端视频轨道 attach 一个测量 VideoSink）。
  static const MethodChannel _decodeProbeChannel =
      MethodChannel('webrtc_decode_probe');

  Future<void> _attachWebRtcDecodeProbe(String trackId) async {
    debugPrint('[WebRtcController] Attaching decode probe for track: $trackId');
    try {
      await _decodeProbeChannel.invokeMethod<void>(
          'attachWebRtcDecodeProbe', {'trackId': trackId});
    } catch (e) {
      debugPrint('[decodeProbe] attach failed: $e');
    }
  }

  Future<void> _detachWebRtcDecodeProbe() async {
    try {
      await _decodeProbeChannel.invokeMethod<void>('detachWebRtcDecodeProbe');
    } catch (e) {
      debugPrint('[decodeProbe] detach failed: $e');
    }
  }

  Future<_DecodeProbeStats?> _getWebRtcDecodeStats() async {
    try {
      final res =
          await _decodeProbeChannel.invokeMethod<dynamic>('getWebRtcDecodeStats');
      if (res is Map) {
        final m = res.cast<String, dynamic>();
        return _DecodeProbeStats(
          lastMs: (m['lastMs'] as num? ?? 0).toDouble(),
          avgMs: (m['avgMs'] as num? ?? 0).toDouble(),
          peakMs: (m['peakMs'] as num? ?? 0).toDouble(),
          totalFrames: (m['totalFrames'] as num? ?? 0).toInt(),
          fpsNow: (m['fpsNow'] as num? ?? 0).toInt(),
          fpsAvg: (m['fpsAvg'] as num? ?? 0).toInt(),
        );
      }
    } catch (e) {
      debugPrint('[decodeProbe] getStats failed: $e');
    }
    return null;
  }

  void _onDataChannel(RTCDataChannel channel) {
    // 被控端也可能主动创建 DataChannel，按标签统一处理。
    if (channel.label == kDataChannelLabel) {
      _dataChannel ??= channel;
      _setupDataChannel(channel);
    } else if (channel.label == kVideoChannelLabel) {
      _videoDataChannel ??= channel;
      _setupVideoDataChannel(channel);
    }
  }

  void _setupDataChannel(RTCDataChannel channel) {
    channel.onMessage = (RTCDataChannelMessage message) {
      if (message.isBinary) {
        try {
          final command = ControlMessage.fromBuffer(message.binary);
          _handleControlMessage(command);
        } catch (e) {
          // ignore: avoid_print
          print('DataChannel message decode failed: $e');
        }
      } else {
        // ignore: avoid_print
        print('DataChannel text message: ${message.text}');
      }
    };
    channel.onDataChannelState = (RTCDataChannelState state) {
      // ignore: avoid_print
      print('DataChannel state: $state');
    };
  }

  void _setupVideoDataChannel(RTCDataChannel channel) {
    channel.onMessage = (RTCDataChannelMessage message) {
      if (message.isBinary) {
        _selfCodecDecoder?.feed(message.binary);
      }
    };
    channel.onDataChannelState = (RTCDataChannelState state) {
      if (state == RTCDataChannelState.RTCDataChannelOpen) {
        _onVideoChannelOpen();
      } else if (state == RTCDataChannelState.RTCDataChannelClosed) {
        _selfCodecDecoder?.setEnabled(false);
      }
    };
  }

  void _onVideoChannelOpen() {
    _ensureSelfCodecDecoder().then((_) {
      _selfCodecDecoder?.setEnabled(_currentStreamMode == streamModeSelfCodec);
    });
  }

  Future<void> _ensureSelfCodecDecoder() async {
    if (_selfCodecDecoder != null || _creatingDecoder) return;
    _creatingDecoder = true;
    try {
      final decoder = SelfCodecDecoder(
        onSize: (w, h) {
          _selfCodecWidth = w;
          _selfCodecHeight = h;
          onResolutionReported?.call(w, h);
        },
        onError: (err) => debugPrint('自编码解码器: $err'),
      );
      final textureId = await decoder.create();
      if (textureId != null) {
        _selfCodecDecoder = decoder;
        onSelfCodecReady?.call(textureId);
      } else {
        // 当前平台（Windows / Linux / Web / iOS 等）无原生硬解能力，回退 WebRTC 媒体流。
        onSelfCodecNotSupported?.call();
      }
    } finally {
      _creatingDecoder = false;
    }
  }

  void _handleControlMessage(ControlMessage msg) {
    switch (msg.action) {
      case Action.REPORT_STREAM_MODE:
        _currentStreamMode = msg.streamMode;
        if (msg.streamMode == streamModeSelfCodec) {
          _ensureSelfCodecDecoder().then((_) {
            _selfCodecDecoder?.setEnabled(true);
          });
        } else {
          _selfCodecDecoder?.setEnabled(false);
        }
        onStreamModeReport?.call(msg.streamMode);
        break;
      case Action.REPORT_RESOLUTION:
        if (msg.width > 0 && msg.height > 0) {
          _selfCodecWidth = msg.width;
          _selfCodecHeight = msg.height;
        }
        onResolutionReported?.call(msg.width, msg.height);
        // 同步帧率信息（当前帧率 + 被控端按刷新率筛选的帧率档位）
        onFpsReport?.call(
            msg.width, msg.height, msg.fps, msg.supportedFps.toList());
        break;
      default:
        // ignore: avoid_print
        print('DataChannel message: ${msg.action}');
        break;
    }
  }

  /// 请求被控端切换屏幕串流模式（SET_STREAM_MODE 指令）。
  /// [mode] 为 0=WebRTC 全托管 / 1=自编码。
  Future<void> sendStreamMode(int mode) async {
    _currentStreamMode = mode;
    if (mode == streamModeSelfCodec) {
      await _ensureSelfCodecDecoder();
      await _selfCodecDecoder?.setEnabled(true);
    } else {
      await _selfCodecDecoder?.setEnabled(false);
    }
    sendControlCommand(ControlCommands.streamMode(mode));
  }

  void _onIceCandidate(RTCIceCandidate candidate) {
    debugPrint('[WebRtcController] local ICE candidate: ${candidate.candidate}');
    final payload = {
      'sdpMid': candidate.sdpMid,
      'sdpMLineIndex': candidate.sdpMLineIndex,
      'candidate': candidate.candidate,
    };
    final msg = SignalMessage.withPayload(
      type: 'ICE_CANDIDATE',
      fromDeviceId: deviceId,
      toDeviceId: targetDeviceId,
      deviceType: 'CONTROLLER',
      payload: payload,
    );
    signaling.send(msg);
  }

  /// 打印 ICE candidate-pair 统计，用于诊断连接失败原因。
  Future<void> _dumpIceStats() async {
    try {
      final stats = await _pc?.getStats();
      final pairs = <String>[];
      for (final report in stats ?? []) {
        if (report.type == 'candidate-pair') {
          final state = report.values['state'] ?? report.values['nominated'];
          pairs.add('${report.values['localCandidateId']}->'
              '${report.values['remoteCandidateId']} state=$state');
        }
      }
      debugPrint('[WebRtcController] ICE Failed. candidate-pair 数量=${pairs.length}');
      for (final p in pairs) {
        debugPrint('[WebRtcController]   pair: $p');
      }
    } catch (e) {
      debugPrint('[WebRtcController] getStats 失败: $e');
    }
  }

  void _onIceConnectionState(RTCIceConnectionState state) {
    // ignore: avoid_print
    print('ICE connection state: $state');
    if (state == RTCIceConnectionState.RTCIceConnectionStateChecking) {
      debugPrint('[WebRtcController] ICE Checking: 正在收集/交换候选，等待连通...');
    } else if (state == RTCIceConnectionState.RTCIceConnectionStateConnected) {
      _connectedAt = DateTime.now().millisecondsSinceEpoch;
      onConnectionEstablished?.call();
    } else if (state == RTCIceConnectionState.RTCIceConnectionStateDisconnected) {
      onIceDisconnected?.call('ICE 连接已断开');
    } else if (state == RTCIceConnectionState.RTCIceConnectionStateFailed) {
      _dumpIceStats();
      onConnectionFailed?.call('ICE 连接失败');
      onDisconnected?.call();
    }
  }

  void _sendOffer(String sdp, {String? authType, String? authValue}) {
    final payload = {'sdp': sdp};
    final msg = SignalMessage.withPayload(
      type: 'OFFER',
      fromDeviceId: deviceId,
      toDeviceId: targetDeviceId,
      deviceType: 'CONTROLLER',
      payload: payload,
      authType: authType,
      authValue: authValue,
    );
    signaling.send(msg);
  }

  /// 处理来自信令服务器的 Answer。
  Future<void> handleAnswer(String sdp) async {
    final answer = RTCSessionDescription(sdp, 'answer');
    await _pc?.setRemoteDescription(answer);
  }

  /// 处理来自信令服务器的 ICE 候选。
  Future<void> handleIceCandidate(Map<String, dynamic> payload) async {
    final candidate = RTCIceCandidate(
      payload['candidate'] as String,
      payload['sdpMid'] as String?,
      payload['sdpMLineIndex'] as int?,
    );
    debugPrint('[WebRtcController] remote ICE candidate: ${candidate.candidate}');
    await _pc?.addCandidate(candidate);
  }

  /// 通过 DataChannel 发送控制指令（protobuf 二进制）。
  void sendControlCommand(ControlMessage command) {
    if (_dataChannel?.state == RTCDataChannelState.RTCDataChannelOpen) {
      debugPrint('WebRtcController: Sending command -> ${command.action}');
      _dataChannel!.send(RTCDataChannelMessage.fromBinary(command.writeToBuffer()));
    }
  }

  /// 请求被控端切换屏幕采集分辨率（SET_RESOLUTION 指令）。
  void sendResolutionChange(int width, int height, int fps) {
    sendControlCommand(ControlCommands.setResolution(width, height, fps));
  }

  /// 上一次统计采样的字节数与时间戳，用于计算每秒网速。
  int _prevBytesReceived = 0;
  int _prevBytesSent = 0;
  int _prevStatsTimestamp = 0;

  /// 上一次采样时的累计解码帧数，用于计算自编码模式下的解码帧率。
  int _prevDecodeCount = 0;

  /// 上一次采样时的累计解码时间（秒）与解码帧数，用于计算 WebRTC 模式下的解码耗时。
  double _prevTotalDecodeTime = 0.0;
  int _prevFramesDecoded = 0;

  /// WebRTC 全托管模式下，由原生 VideoSink 探针实测的解码耗时统计缓存。
  _DecodeProbeStats? _webRtcDecodeProbe;

  /// 解码器上报的真实分辨率（自编码模式下 WebRTC 视频统计为空，需用此覆盖）。
  int _selfCodecWidth = 0;
  int _selfCodecHeight = 0;

  /// 连接建立时的时间戳（毫秒），用于计算连接时长。
  int? _connectedAt;

  /// 采集连接统计信息，回调格式化后的文本（对应 Android 端 updateStats）。
  ///
  /// 包含：分辨率/帧率/延迟/解码格式、抖动、丢包率、丢帧、
  /// 每秒上下行网速、连接类型(P2P/TURN)+候选协议、连接时长、
  /// 控制 DataChannel 状态与收发消息数。
  Future<String> getStatsText() async {
    if (_pc == null) return '';
    final reports = await _pc!.getStats();

    dynamic width = '-';
    dynamic height = '-';
    dynamic fps = '-';
    dynamic delay = '-';
    dynamic codec = '-';
    dynamic jitter = '-';
    dynamic lossRate = '-';
    dynamic framesDropped = '-';

    int bytesReceived = 0;
    int bytesSent = 0;
    String? localCandidateId;
    String? remoteCandidateId;
    bool hasNominatedPair = false;

    // 控制 DataChannel 统计（仅统计与对端的控制通道）。
    int dcMessagesSent = 0;
    int dcMessagesReceived = 0;

    double currentTotalDecodeTime = 0.0;
    int currentFramesDecoded = 0;

    // 与上次采样的时间差（秒），供循环内估算解码帧率，也供下方计算每秒网速。
    final now = DateTime.now().millisecondsSinceEpoch;
    final double dtSec =
        _prevStatsTimestamp != 0 ? (now - _prevStatsTimestamp) / 1000.0 : 0;

    for (final report in reports) {
      final values = report.values;
      final type = report.type;
      if (type == 'inbound-rtp' && values['kind'] == 'video') {
        // 关键数据打印，用于排查 totalDecodeTime 是否存在于当前平台的统计中
        debugPrint('[WebRtcController] inbound-rtp: totalDecodeTime=${values['totalDecodeTime']}, '
            'googDecodeMs=${values['googDecodeMs']}, '
            'framesDecoded=${values['framesDecoded']}, '
            'fps=${values['framesPerSecond']}');

        width = values['frameWidth'] ?? '-';
        height = values['frameHeight'] ?? '-';
        fps = values['framesPerSecond'] ?? '-';

        final j = values['jitter'];
        if (j is num) jitter = (j * 1000).toStringAsFixed(0);

        final pr = values['packetsReceived'];
        final pl = values['packetsLost'];
        if (pr is num && pl is num) {
          final total = pr + pl;
          lossRate = total > 0 ? ((pl / total) * 100).toStringAsFixed(1) : '0.0';
        }

        final fd = values['framesDropped'];
        if (fd is num) framesDropped = fd;

        // 核心：解析解码统计（兼容标准字段与旧版 Google 私有字段）
        currentTotalDecodeTime = (values['totalDecodeTime'] as num?)?.toDouble() ??
            ((values['googDecodeMs'] as num?)?.toDouble() ?? 0.0) / 1000.0;
        currentFramesDecoded = (values['framesDecoded'] as num?)?.toInt() ??
            (values['googFramesDecoded'] as num?)?.toInt() ?? 0;

        final codecId = values['codecId'];
        if (codecId != null) {
          final codecReport = reports.where((r) => r.id == codecId).firstOrNull;
          final mime = codecReport?.values['mimeType'];
          if (mime is String && mime.startsWith('video/')) {
            codec = mime.substring(6);
          }
        }
      } else if (type == 'candidate-pair') {
        if (values['nominated'] == true) {
          hasNominatedPair = true;
          final rtt = values['currentRoundTripTime'];
          if (rtt is num) {
            delay = (rtt * 1000).toStringAsFixed(0);
          }
          // candidate-pair 的 bytesReceived/bytesSent 为整条连接（视频+DataChannel+ICE）的累计值。
          final br = values['bytesReceived'];
          final bs = values['bytesSent'];
          if (br is num) bytesReceived = br.toInt();
          if (bs is num) bytesSent = bs.toInt();
          final lc = values['localCandidateId'];
          final rc = values['remoteCandidateId'];
          if (lc is String) localCandidateId = lc;
          if (rc is String) remoteCandidateId = rc;
        }
      } else if (type == 'data-channel') {
        if (values['label'] == kDataChannelLabel) {
          final ms = values['messagesSent'];
          final mr = values['messagesReceived'];
          if (ms is num) dcMessagesSent = ms.toInt();
          if (mr is num) dcMessagesReceived = mr.toInt();
        }
      }
    }

    // 计算每秒网速（与上次采样差值）。
    String downSpeed = '-';
    String upSpeed = '-';
    if (dtSec > 0) {
      final downBps = (bytesReceived - _prevBytesReceived) / dtSec;
      final upBps = (bytesSent - _prevBytesSent) / dtSec;
      downSpeed = _formatSpeed(downBps);
      upSpeed = _formatSpeed(upBps);
    }
    _prevBytesReceived = bytesReceived;
    _prevBytesSent = bytesSent;
    _prevStatsTimestamp = now;

    // 连接类型（P2P/TURN）与候选协议（udp/tcp）。
    String connType = '-';
    String protocol = '-';
    if (hasNominatedPair) {
      connType =
          _resolveConnectionType(reports, localCandidateId, remoteCandidateId);
      protocol = _resolveProtocol(reports, localCandidateId, remoteCandidateId);
    }

    // 连接时长。
    String duration = '-';
    if (_connectedAt != null) {
      final secs = ((now - _connectedAt!) / 1000).floor();
      final m = (secs ~/ 60).toString().padLeft(2, '0');
      final s = (secs % 60).toString().padLeft(2, '0');
      duration = '$m:$s';
    }

    // 控制 DataChannel 状态。
    final dcState = _dataChannel?.state;
    final dcStatus = dcState == RTCDataChannelState.RTCDataChannelOpen
        ? '已连接'
        : (dcState == null ? '未连接' : dcState.name);

    // —— 分模式统计解码耗时 ——
    String? decodeInfo;
    // 基础行要展示的解码耗时：WebRTC 模式用 inbound-rtp 估算，自编码模式用原生平均。
    double nativeAvg = 0;

    if (_currentStreamMode == streamModeSelfCodec) {
      // 【自编码模式】：视频走 DataChannel 透传裸码流，WebRTC 的视频统计为空。
      // 使用原生解码器上报的真实分辨率、帧率与耗时。
      if (_selfCodecDecoder != null) {
        final ds = await _selfCodecDecoder!.getStats();
        if (ds != null) {
          final last = (ds['lastMs'] as num?)?.toDouble() ?? 0;
          final avg = (ds['avgMs'] as num?)?.toDouble() ?? 0;
          final peak = (ds['maxMs'] as num?)?.toDouble() ?? 0;
          final cnt = (ds['count'] as num?)?.toInt() ?? 0;
          nativeAvg = avg;
          if (_selfCodecWidth > 0 && _selfCodecHeight > 0) {
            width = _selfCodecWidth;
            height = _selfCodecHeight;
          }
          double decodeFps = 0;
          if (dtSec > 0 && cnt > 0) {
            decodeFps = (cnt - _prevDecodeCount) / dtSec;
          }
          _prevDecodeCount = cnt;
          if (decodeFps > 0) fps = decodeFps.round();
          decodeInfo = '解码耗时: ${last.toStringAsFixed(1)} ms  平均: ${avg.toStringAsFixed(1)} ms  峰值: ${peak.toStringAsFixed(1)} ms\n'
              '解码帧率: ${decodeFps.toStringAsFixed(0)} fps  已解码: $cnt 帧';
        }
      }
      // 自编码模式下，WebRTC 的相关计数建议重置，避免切回时出现跳变。
      _prevTotalDecodeTime = currentTotalDecodeTime;
      _prevFramesDecoded = currentFramesDecoded;
    } else {
      // 【WebRTC 模式】：优先使用标准的 getStats() 增量计算耗时。
      double avg = 0;
      if (currentFramesDecoded > 0) {
        if (_prevFramesDecoded > 0 && currentFramesDecoded > _prevFramesDecoded) {
          final deltaMs = (currentTotalDecodeTime - _prevTotalDecodeTime) * 1000.0;
          final deltaFrames = currentFramesDecoded - _prevFramesDecoded;
          if (deltaFrames > 0) avg = deltaMs / deltaFrames;
        } else if (currentTotalDecodeTime > 0) {
          // 兜底：第一次采样或帧数无增量时，用全量平均作为初始参考
          avg = (currentTotalDecodeTime * 1000.0) / currentFramesDecoded;
        }
      }

      if (avg > 0) {
        nativeAvg = avg;
        decodeInfo = '解码耗时 (stats): ${avg.toStringAsFixed(1)} ms\n'
            '解码帧率: $fps fps  已解码: $currentFramesDecoded 帧';
      } else {
        // 备选方案：如果 getStats 没报数据（部分平台/环境限制），则回退到原生 VideoSink 探针实测模式。
        _webRtcDecodeProbe = await _getWebRtcDecodeStats();
        final p = _webRtcDecodeProbe;
        if (p != null && p.totalFrames > 0) {
          nativeAvg = p.avgMs;
          decodeInfo =
              '解码耗时 (probe): ${p.lastMs.toStringAsFixed(1)} ms  平均: ${p.avgMs.toStringAsFixed(1)} ms  峰值: ${p.peakMs.toStringAsFixed(1)} ms\n'
              '解码帧率: ${p.fpsNow} fps (平均 ${p.fpsAvg} fps)  已解码: ${p.totalFrames} 帧';
        }
      }
      // WebRTC 模式下，自编码的计数重置。
      _prevDecodeCount = 0;
      _prevTotalDecodeTime = currentTotalDecodeTime;
      _prevFramesDecoded = currentFramesDecoded;
    }

    String decodeTimeText = '-';
    if (decodeInfo != null && nativeAvg > 0) {
      decodeTimeText = '${nativeAvg.toStringAsFixed(1)} ms';
    }

    final base = '分辨率: ${width}x$height  帧率: $fps  延迟: $delay ms  解码耗时: $decodeTimeText\n'
        '解码格式: $codec  抖动: $jitter ms  丢包: $lossRate%\n'
        '丢帧: $framesDropped  ↓下载: $downSpeed  ↑上传: $upSpeed\n'
        '连接类型: $connType ($protocol)  时长: $duration\n'
        '控制通道: $dcStatus  收发: $dcMessagesSent/$dcMessagesReceived';

    return decodeInfo != null ? '$base\n$decodeInfo' : base;
  }

  /// 依据选定候选对的本地/远端候选类型，返回 P2P / TURN 中继描述。
  String _resolveConnectionType(
    List<StatsReport> reports,
    String? localCandidateId,
    String? remoteCandidateId,
  ) {
    String? typeOf(String? id) {
      if (id == null) return null;
      final report = reports.where((r) => r.id == id).firstOrNull;
      final t = report?.values['candidateType'];
      return t is String ? t : null;
    }

    final local = typeOf(localCandidateId);
    final remote = typeOf(remoteCandidateId);
    final isRelay = local == 'relay' || remote == 'relay';

    if (isRelay) {
      // 进一步用本地候选具体类型细化（优先说明本端是否经 TURN 中继）。
      if (local == 'relay') return 'TURN 中继 (本端经服务器)';
      return 'TURN 中继';
    }
    // host: 同一局域网直连; srflx/prflx: 经 NAT 打洞的 P2P。
    return 'P2P 直连';
  }

  /// 返回选定候选对的传输协议（udp/tcp）。
  String _resolveProtocol(
    List<StatsReport> reports,
    String? localCandidateId,
    String? remoteCandidateId,
  ) {
    String protoOf(String? id) {
      if (id == null) return '-';
      final report = reports.where((r) => r.id == id).firstOrNull;
      final p = report?.values['protocol'];
      return p is String ? p : '-';
    }

    final local = protoOf(localCandidateId);
    final remote = protoOf(remoteCandidateId);
    if (local != '-' && remote != '-' && local != remote) {
      return '$local/$remote';
    }
    return local != '-' ? local : remote;
  }

  /// 将字节/秒格式化为人类可读字符串（B/s、KB/s、MB/s）。
  String _formatSpeed(double bytesPerSecond) {
    if (bytesPerSecond >= 1024 * 1024) {
      return '${(bytesPerSecond / (1024 * 1024)).toStringAsFixed(1)} MB/s';
    } else if (bytesPerSecond >= 1024) {
      return '${(bytesPerSecond / 1024).toStringAsFixed(1)} KB/s';
    }
    return '${bytesPerSecond.toStringAsFixed(0)} B/s';
  }

  /// 释放所有资源。
  Future<void> close() async {
    try {
      await _dataChannel?.close();
    } catch (_) {}
    try {
      await _detachWebRtcDecodeProbe();
    } catch (_) {}
    try {
      await _pc?.close();
    } catch (_) {}
    try {
      await renderer.dispose();
    } catch (_) {}
    _dataChannel = null;
    try {
      await _videoDataChannel?.close();
    } catch (_) {}
    _videoDataChannel = null;
    try {
      await _selfCodecDecoder?.dispose();
    } catch (_) {}
    _selfCodecDecoder = null;
    _currentStreamMode = streamModeWebRtc;
    onSelfCodecLost?.call();
    onSelfCodecReady = null;
    onStreamModeReport = null;
    onResolutionReported = null;
    onFpsReport = null;
    onSelfCodecNotSupported = null;
    _pc = null;
    // 重置网速统计基线，避免下次连接首帧显示错误的瞬时速率。
    _prevBytesReceived = 0;
    _prevBytesSent = 0;
    _prevStatsTimestamp = 0;
    _prevDecodeCount = 0;
    _prevTotalDecodeTime = 0.0;
    _prevFramesDecoded = 0;
    _webRtcDecodeProbe = null;
    _selfCodecWidth = 0;
    _selfCodecHeight = 0;
    _connectedAt = null;
  }
}
