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

import '../../../core/proto/control_message.pb.dart';
import '../../auth/data/auth_providers.dart';
import '../data/remote_controller.dart';
import '../data/self_codec_decoder.dart';
import '../data/video_recorder.dart';
import '../domain/binding_device.dart';
import '../domain/connection_session_state.dart';

part 'connection_controller.g.dart';

/// 连接控制会话控制器：编排信令 + WebRTC，管理控制端全部 UI 状态。
@Riverpod(keepAlive: true)
class ConnectionController extends _$ConnectionController {
  /// 与 Windows 原生窗口通信的通道（用于按视频比例调整窗口高度）。
  static const MethodChannel _windowChannel = MethodChannel('app/window');

  RemoteController? _remote;
  RTCVideoRenderer? _renderer;
  final VideoRecorder _videoRecorder = VideoRecorder();

  /// 记录上一次已应用的视频宽高比，避免重复调整窗口。
  double _lastResizedAspect = 0;

  @override
  ConnectionSessionState build() {
    ref.onDispose(() {
      _videoRecorder.dispose();
      _remote?.disconnect();
    });
    return const ConnectionSessionState(status: '状态: 已停止');
  }

  void _setStatus(String status) => state = state.copyWith(status: status);

  void _alert(String message) => state = state.copyWith(alert: message);

  void _clearAlert() => state = state.copyWith(alert: null);

  /// 仅建立信令（WebSocket）连接，**不**发起远程控制。
  ///
  /// 进入设置页即可调用；重复调用会被忽略。
  Future<void> connectSignaling({required String serverUrl}) async {
    if (serverUrl.isEmpty) {
      _alert('信令服务器地址为空');
      return;
    }
    if (_remote != null || state.signalingConnected) return;

    final authRepository = ref.read(authRepositoryProvider);
    state = state.copyWith(connecting: true, status: '状态: 正在连接信令服务器...');

    _remote = RemoteController(
      serverUrl: serverUrl,
      authRepository: authRepository,
    );
    _wireRemoteCallbacks();
    await _remote!.connectSignaling();
  }

  /// 发起远程控制：需信令已就绪，向目标设备创建 Offer。
  Future<void> startControl({
    required String targetDeviceId,
    required String authType,
    required String authValue,
  }) async {
    if (targetDeviceId.isEmpty) {
      _alert('请填写目标设备ID');
      return;
    }
    if (!state.signalingConnected || _remote == null) {
      _alert('信令未就绪，请稍后重试');
      return;
    }
    state = state.copyWith(connecting: true, status: '状态: 正在发起连接...');
    _remote!.startControl(
      target: targetDeviceId,
      authType: authType,
      authValue: authValue,
    );
  }

  /// 拉取已绑定设备列表，并合并在线设备状态。
  ///
  /// 参考 Android 控制端的 [MainViewModel.loadBindings] / [getOnlineDevices]，
  /// 用在线列表标记绑定设备是否可立即连接。
  Future<void> loadDevices() async {
    final authRepository = ref.read(authRepositoryProvider);
    state = state.copyWith(deviceRefreshing: true, deviceError: null);
    try {
      final bindings = await authRepository.getBindings();
      List<BindingDevice> online = const [];
      try {
        online = await authRepository.getOnlineDevices();
      } on Object {
        // 在线列表接口失败时，仍展示全部绑定（仅不标记在线）。
      }
      final onlineUids = {for (final d in online) d.deviceUid};
      final merged = [
        for (final b in bindings)
          b.copyWith(online: onlineUids.contains(b.deviceUid)),
      ];
      final stillSelected = merged
          .where((b) => b.deviceUid == state.selectedDeviceUid)
          .isNotEmpty;
      state = state.copyWith(
        bindings: merged,
        onlineUids: onlineUids,
        deviceRefreshing: false,
        selectedDeviceUid: stillSelected ? state.selectedDeviceUid : null,
      );
    } on Object catch (e) {
      debugPrint(e.toString());
      state = state.copyWith(
        deviceRefreshing: false,
        deviceError: '加载绑定设备失败：$e',
      );
    }
  }

  /// 在绑定设备列表中选择一个目标设备（仅记录选择，不下发连接）。
  void selectDevice(String uid) {
    if (state.selectedDeviceUid == uid) return;
    state = state.copyWith(selectedDeviceUid: uid);
  }

  /// 当前选中的绑定设备（无则返回 null）。
  BindingDevice? get selectedDevice {
    final uid = state.selectedDeviceUid;
    if (uid == null) return null;
    for (final b in state.bindings) {
      if (b.deviceUid == uid) return b;
    }
    return null;
  }

  /// 向选中的绑定设备发起远程控制。
  ///
  /// 鉴权方式取自 [BindingDevice.authType]，凭据由 UI 的鉴权对话框收集后传入。
  Future<void> connectSelectedDevice({
    required String authType,
    required String authValue,
  }) async {
    final target = selectedDevice;
    if (target == null) {
      _alert('请先选择一个绑定的设备');
      return;
    }
    if (!target.online) {
      _alert('设备「${target.name}」当前不在线，无法连接');
      return;
    }
    await startControl(
      targetDeviceId: target.deviceUid,
      authType: authType,
      authValue: authValue,
    );
  }

  /// 使用被控端展示的配对码建立绑定关系，并刷新绑定设备列表。
  Future<bool> redeemPairingCode(String code) async {
    final trimmed = code.trim();
    if (trimmed.isEmpty) {
      state = state.copyWith(redeemError: '请输入配对码');
      return false;
    }
    final authRepository = ref.read(authRepositoryProvider);
    state = state.copyWith(redeeming: true, redeemError: null);
    try {
      await authRepository.redeemPairingCode(trimmed);
      state = state.copyWith(redeeming: false);
      await loadDevices();
      return true;
    } on Object catch (e) {
      state = state.copyWith(redeeming: false, redeemError: '绑定失败：$e');
      return false;
    }
  }

  /// 清除配对码兑换错误提示。
  void clearRedeemError() => state.copyWith(redeemError: null);

  void _wireRemoteCallbacks() {
    final remote = _remote!;
    remote.onStatusChanged = _setStatus;
    remote.onRegistered = (myDeviceId) {
      state = state.copyWith(
        signalingConnected: true,
        connecting: false,
        myDeviceId: myDeviceId,
      );
    };
    remote.onConnectionEstablished = () {
      state = state.copyWith(
        connected: true,
        connecting: false,
        status: '状态: 已连接 - 远程控制中',
      );
    };
    remote.onConnectionFailed = (error) {
      state = state.copyWith(connecting: false);
      _alert('连接失败：$error');
    };
    remote.onDisconnected = () {
      state = state.copyWith(
        connected: false,
        connecting: false,
        signalingConnected: false,
        myDeviceId: null,
      );
      _setStatus('状态: 远端已断开');
    };
    // 以下三种情况仅结束远程控制，保留信令连接以便重新发起。
    remote.onIceDisconnected = (message) {
      _alert(message);
      stopControl();
    };
    remote.onTargetOffline = (message) {
      _alert(message);
      stopControl();
    };
    remote.onConnectionRejected = (message) {
      _alert(message);
      stopControl();
    };
    remote.onRemoteStream = (renderer) {
      _renderer = renderer;
      state = state.copyWith(renderer: renderer);
      renderer.addListener(_onRendererUpdate);
      if (state.pendingRecordStart) {
        state = state.copyWith(pendingRecordStart: false);
        _startRecording();
      }
    };
    remote.onStats = (stats) => state = state.copyWith(stats: stats);
    remote.onSelfCodecReady = (textureId) {
      state = state.copyWith(
        selfCodecTextureId: textureId,
        selfCodecReady: true,
      );
    };
    remote.onSelfCodecLost = () {
      state = state.copyWith(selfCodecReady: false, selfCodecTextureId: null);
    };
    remote.onStreamModeReport = (mode) {
      state = state.copyWith(streamMode: mode);
      if (mode == SelfCodecDecoder.streamModeWebRtc &&
          state.pendingRecordStart) {
        state = state.copyWith(pendingRecordStart: false);
        _startRecording();
      }
    };
    remote.onResolutionReported = (w, h) {
      if (w > 0 && h > 0) {
        final aspect = w / h;
        state = state.copyWith(videoAspect: aspect);
        _resizeWindowToAspect(aspect);
      }
    };
    remote.onFpsReport = (w, h, fps, supportedFps) {
      state = state.copyWith(
        lastReportedWidth: w > 0 ? w : state.lastReportedWidth,
        lastReportedHeight: h > 0 ? h : state.lastReportedHeight,
        currentFps: fps > 0 ? fps : state.currentFps,
        fpsOptions: supportedFps.isNotEmpty ? supportedFps : state.fpsOptions,
      );
    };
    remote.onSelfCodecNotSupported = () {
      state = state.copyWith(selfCodecSupported: false);
      _alert('当前平台不支持自编码硬解，已回退到 WebRTC 媒体流。');
    };
    remote.onTokenExpired = () {
      _alert('登录已失效，请重新登录后再连接。');
      _resetLogin();
    };
    remote.onForceLogout = () {
      _alert('账号已在其他位置登录，已强制下线。');
      _resetLogin();
    };
  }

  Future<void> _resetLogin() async {
    await ref.read(authRepositoryProvider).clear();
    await disconnect();
    state = state.copyWith(connected: false, connecting: false);
  }

  void _onRendererUpdate() {
    final w = _renderer?.value.width ?? 0;
    final h = _renderer?.value.height ?? 0;
    if (w > 0 && h > 0) {
      final aspect = w / h;
      state = state.copyWith(videoAspect: aspect);
      _resizeWindowToAspect(aspect);
    }
  }

  /// Windows 端：保持窗口宽度不变，按视频宽高比调整窗口高度。
  void _resizeWindowToAspect(double aspect) {
    if (kIsWeb || defaultTargetPlatform != TargetPlatform.windows) return;
    if (aspect <= 0) return;
    if ((aspect - _lastResizedAspect).abs() < 0.001) return;
    _lastResizedAspect = aspect;
    _windowChannel.invokeMethod('resizeToVideoAspect', aspect);
  }

  /// 切换分辨率：写入状态并下发指令。
  void selectResolution(int index) {
    state = state.copyWith(selectedResolution: index);
    final o = state.resolutionOptions[index];
    _remote?.sendResolutionChange(
      o['width'] as int,
      o['height'] as int,
      o['fps'] as int,
    );
  }

  /// 切换帧率：仅切帧率，分辨率保持不变。
  void selectFps(int fps) {
    if (fps <= 0 || fps == state.currentFps) return;
    _remote?.sendResolutionChange(
      state.lastReportedWidth,
      state.lastReportedHeight,
      fps,
    );
  }

  /// 切换串流模式：WebRTC 全托管 <-> 自编码。
  void toggleStreamMode() {
    if (!state.selfCodecSupported) {
      _alert('当前平台不支持自编码硬解。');
      return;
    }
    final next = state.streamMode == SelfCodecDecoder.streamModeSelfCodec
        ? SelfCodecDecoder.streamModeWebRtc
        : SelfCodecDecoder.streamModeSelfCodec;
    state = state.copyWith(streamMode: next);
    _remote?.sendStreamMode(next);
  }

  /// 切换远程视频录制：开始 / 停止。
  Future<void> toggleRecord() async {
    if (state.recording) {
      await _stopRecording();
      return;
    }
    final renderer = _renderer;
    if (renderer == null) {
      _alert('尚未连接或没有视频画面，无法录制');
      return;
    }
    if (state.streamMode == SelfCodecDecoder.streamModeSelfCodec) {
      // 自编码模式下没有 WebRTC 视频轨道，先切回标准模式再开始录制。
      state = state.copyWith(
        pendingRecordStart: true,
        recordStatus: '正在切回标准模式以开始录制...',
      );
      _remote?.sendStreamMode(SelfCodecDecoder.streamModeWebRtc);
      return;
    }
    await _startRecording();
  }

  Future<void> _startRecording() async {
    if (state.recording) return;
    final stream = _renderer?.srcObject;
    if (stream == null) {
      _alert('尚未接收到视频画面，无法录制');
      return;
    }
    try {
      final ok = await _videoRecorder.start(stream);
      if (ok) {
        state = state.copyWith(recording: true, recordStatus: '录制中...');
      }
    } catch (e) {
      state = state.copyWith(recordStatus: '');
      _alert('开始录制失败：$e');
    }
  }

  Future<void> _stopRecording() async {
    final path = await _videoRecorder.stop();
    state = state.copyWith(
      recording: false,
      recordStatus: path != null ? '已保存：$path' : '录制已停止',
    );
  }

  /// 发送控制指令（protobuf 二进制）。
  void sendControlCommand(ControlMessage command) {
    _remote?.sendControlCommand(command);
  }

  /// 结束远程控制但保持信令连接，便于重新选择设备发起连接。
  Future<void> stopControl() async {
    await _videoRecorder.dispose();
    await _remote?.stopControl();
    _renderer?.removeListener(_onRendererUpdate);
    _renderer = null;
    _lastResizedAspect = 0;
    final signalingAlive = state.signalingConnected;
    state = ConnectionSessionState(
      status: signalingAlive ? '状态: 已连接信令服务器' : '状态: 已停止',
      signalingConnected: signalingAlive,
      myDeviceId: state.myDeviceId,
      alert: state.alert,
    );
  }

  /// 断开全部连接（含信令）并复位 UI 状态。
  Future<void> disconnect() async {
    await _videoRecorder.dispose();
    await _remote?.disconnect();
    _remote = null;
    _renderer?.removeListener(_onRendererUpdate);
    _renderer = null;
    _lastResizedAspect = 0;
    state = ConnectionSessionState(status: '状态: 已停止', alert: state.alert);
  }

  /// 消费一次性提示消息（UI 展示后调用）。
  void consumeAlert() => _clearAlert();
}
