import 'package:fis_common/index.dart';
import 'package:fis_common/logger/logger.dart';
import 'package:fis_jsonrpc/rpc.dart';
import 'package:fis_ui/index.dart';
import 'package:flutter/widgets.dart';
import 'package:flyinsono/architecture/services/entity/hardware_setting.dart';
import 'package:flyinsono/architecture/services/modules/hardware_setting_configuration.dart';
import 'package:flyinsono/architecture/states/states.dart';
import 'package:flyinsono/managers/interfaces/entities/consultation_member.dart';
import 'package:flyinsono/managers/interfaces/rtmp_mock_rtc.dart';
import 'package:flyinsono/views/desktop/real_time_consultation/live_consultation/controller.dart';
import 'package:flyinsono/views/desktop/real_time_consultation/live_consultation/entitys/play_channel.dart';
import 'package:flyinsono/views/desktop/real_time_consultation/live_consultation/state.dart';
import 'package:fis_lib_media_rt/fis_lib_media_rt.dart';
import 'package:fis_lib_media_rt/implementations/trtc/room.dart';
import 'package:tencent_trtc_cloud/trtc_cloud_listener.dart';
import 'package:get/get.dart';
import 'package:permission_handler/permission_handler.dart';

class MediaController {
  LiveConsultationController controller;
  LiveConsulationState get state => controller.state;
  IPublisher? _publisher;
  IPlayer? _player;
  bool _entered = false;
  bool _isExit = false;
  bool _isLocalStreamPublishStarted = false;
  late final BaseRoom _room;
  VideoDeviceOutputInfo? cameraDeviceInfo;
  MediaController(this.controller) {
    _checkPermission();
  }

  void init() {
    /// 本地硬件设置持久化缓存服务
    HardwareSettingService hardwareSettingService =
        Get.find<HardwareSettingService>();
    hardwareSettingService.init();

    ///初始化设备信息
    _initDeviceInfo();

    ///初始化房间的一些事件监听
    _initRoom();

    ///进入房间
    _enter();
  }

  ///退出房间
  Future<void> exit() async {
    if (!_isLocalStreamPublishStarted) {
      // 未开始推流，等待3秒，如果立即退出将会无法结束 Stream 视频流
      await Future.delayed(Duration(seconds: 3));
    }
    if (_isExit) {
      return;
    }
    try {
      await stopLocal();
      _room.exit();
      _isExit = true;
    } catch (e) {
      logger.e('MediaController exit ex:', e);
    }
  }

  ///开启本地预览推流
  void startLocal() async {
    state.playChannels.update(Store.user.code, (value) {
      value.started = true;
      return value;
    });
    // 获取缓存的推荐硬件设置
    HardwareSetting hardwareSetting = HardwareSetting.ins;
    final String idealCameraName = hardwareSetting.idealWebVideoInputDeviceName;
    final String idealMicrophoneName =
        hardwareSetting.idealWebAudioInputDeviceName;

    _publisher!.channels.first.readyStateChanged.addListener((sender, e) async {
      if (e) {
        WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
          Future.delayed(const Duration(milliseconds: 200), () {
            _publisher!.startLocal();
          });
        });
      }
    });
    print("⭐⭐ 预设硬件配置 idealCameraName: $idealCameraName");
    // 这里缺个事件，收到通知后可设置分辨率
    // 这里是TRTC SDK设计原因，所以要先播放才能改分辨率，是否魔改以后再说
    _publisher!.setProfile(PublisherProfile(
        resolutionMode: ResolutionMode.landscape,
        resolution: Resolutions.sd_480p,
        frameRate: 10,
        idealCameraName: idealCameraName,
        idealMicrophoneName: idealMicrophoneName));
  }

  ///开启或关闭本地视频
  void switchVideoOpen(bool isOpen) {
    var userCode = Store.user.code;
    var memberStatus = state.memberStatus[userCode];
    if (memberStatus != null) {
      state.memberStatus.update(userCode, (value) {
        value.videoOpend = isOpen;
        return value;
      });
    }
    if (state.playChannels.containsKey(userCode)) {
      // state.playChannels.update(userCode, (value) {
      //   value.started = isOpen;
      //   var channel = value.channel;
      //   if (channel != null) {
      //     channel.setVideoMute(!isOpen);
      //   }
      //   return value;
      // });
    }
  }

  ///设置静音
  void setAudioMute(bool isMute, String userCode) {
    if (state.playChannels.containsKey(userCode)) {
      state.playChannels.update(userCode, (value) {
        if (value.channel != null) {
          value.channel!.setAudioMute(isMute);
        }
        return value;
      });
    }
  }

  ///停止本地预览推流
  Future<void> stopLocal() async {
    await _publisher?.stopLocal();
    if (state.playChannels.containsKey(Store.user.code)) {
      state.playChannels.update(Store.user.code, (value) {
        value.started = false;
        return value;
      });
    }
  }

  IChannel? getMemberPreviewChannel(ConsultationMember member) {
    if (member.memberType == LiveMemberEnum.Device) {
      return state.isSwitchCameraDevice
          ? controller.state.deviceDesktopChannel
          : controller.state.deviceCameraChannel;
    }
    var playChannels = controller.state.playChannels;
    if (playChannels.containsKey(member.id) &&
        playChannels[member.id]!.channel != null &&
        playChannels[member.id]!.started) {
      return playChannels[member.id]!.channel!;
    }
    return null;
  }

  void _initRoom() {
    var liveConsultation = state.liveConsultation;
    FRTMediaConfig.trtc.appid = liveConsultation.appId;
    _room = FRealTimeMedia.createRoom(
      liveConsultation.roomNo.toString(),
      FRTMediaConfig.serviceType,
    );
    _room.entered.addListener(_onEntered);
    _room.exited.addListener(_onExited);
  }

  void _onEntered(Object sender, void e) {
    _initPublisher();
    _initPlayer();
    if (_room is TrtcRoom) {
      (_room as TrtcRoom).events.once(TRTCCloudListener.onStreamPublish,
          (param) async {
        _isLocalStreamPublishStarted = true;
      });
    }
    if (!_entered) {
      _entered = true;
      startLocal();
    }
  }

  void _initPublisher() {
    if (_publisher != null) return;
    _publisher = _room.createPublisher();
    state.playChannels[Store.user.code] =
        PlayChannelInfo(_publisher!.channels.first, started: false);
  }

  void _initPlayer() {
    if (_player != null) return;
    _player = _room.createPlayer();
    _player!.channelAdded.addListener(_onChannelAdded);
    _player!.channelRemoved.addListener(_onChannelRemoved);
  }

  void _onChannelAdded(Object s, IPlayChannel channel) async {
    channel as BasePlayChannel;
    ConsultationMember device = controller.state.memberStatus.values
        .firstWhere((element) => element.memberType == LiveMemberEnum.Device);
    String userId = channel.member.userId ?? '';
    bool isExist = state.playChannels.containsKey(userId); // 是否已经存在该视频流
    if (isExist) {
      state.playChannels.update(userId, (value) {
        value.channel = channel;
        value.started = true;
        return value;
      });
    } else {
      state.playChannels[userId] = PlayChannelInfo(channel, started: true);
    }

    bool kIsCamera = cameraDeviceInfo != null &&
        cameraDeviceInfo!.videoDeviceId == userId; // 当前为摄像头流
    bool kIsDesktop = state.desktopDeviceInfo != null &&
        state.desktopDeviceInfo!.videoDeviceId == userId; // 当前为主画面流
    if (kIsCamera) {
      state.deviceCameraChannel = channel;
    } else if (kIsDesktop) {
      state.deviceDesktopChannel = channel;
      controller.loadingController.stopLoading();
      controller.onDeviceChannelAdd.emit(this, channel);
      channel.onVideoInfo.addListener(_handleVideoInfoCallback);
      channel.onVideoLost.addListener(_handleVideoLostCallback);
      if (device.mergedChannel) {
        controller.state.isMergedMode = true;
        controller.state.isNeedCropDeviceDesktop = true;
        int fullViewWidth = device.mergedVideoOutputWidth;
        int fullViewHeight = device.mergedVideoOutputHeight;
        VideoDeviceOutputInfo mainView = device.videoDeviceInfos!.firstWhere(
            (element) =>
                element.videoDeviceSourceType ==
                VideoDeviceSourceTypeEnum.Desktop);
        controller.state.mainViewRectInMergedMode = Rect.fromLTWH(
            0,
            0,
            mainView.outputWidth / fullViewWidth,
            mainView.outputHeight / fullViewHeight);
        // 如果此时 fullViewWidth、fullViewHeight 的参数不正确，需要拿到真实回调后再次设置 controller.state.mainViewRectInMergedMode
      } else {
        controller.state.isMergedMode = false;
        VideoDeviceOutputInfo mainView = device.videoDeviceInfos!.firstWhere(
            (element) =>
                element.videoDeviceSourceType ==
                VideoDeviceSourceTypeEnum.Desktop);
        Size realSize = selectResolution(Size(
            mainView.outputWidth.toDouble(), mainView.outputHeight.toDouble()));
        if (realSize.width.toInt() == mainView.outputWidth &&
            realSize.height.toInt() == mainView.outputHeight) {
          controller.state.isNeedCropDeviceDesktop = false;
        } else {
          controller.state.isNeedCropDeviceDesktop = true;
          controller.state.mainViewRectInMergedMode = Rect.fromLTWH(
              0,
              0,
              mainView.outputWidth / realSize.width,
              mainView.outputHeight / realSize.height);
        }
      }
    }
    channel.readyStateChanged.addListener((sender, e) {
      if (e) {
        WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
          Future.delayed(const Duration(milliseconds: 200), () {
            channel.play();
          });
        });
      }
    });
  }

  /// 处理实际视频大小回调
  void _handleVideoInfoCallback(_, Size size) {
    // print('通过实际总尺寸修正 size:$size');

    /// FIXME 此时的 controller.state.memberStatus 为旧数据，需要提前更新

    ConsultationMember device = controller.state.memberStatus.values
        .firstWhere((element) => element.memberType == LiveMemberEnum.Device);
    VideoDeviceOutputInfo mainView = device.videoDeviceInfos!.firstWhere(
        (element) =>
            element.videoDeviceSourceType == VideoDeviceSourceTypeEnum.Desktop);
    controller.state.mainViewRectInMergedMode = Rect.fromLTWH(0, 0,
        mainView.outputWidth / size.width, mainView.outputHeight / size.height);

    // 特殊情况的修正：RTMP 环境下，特殊机型例如 X1 等，接口返回的主画面尺寸不正确，需要通过实际尺寸修正
    // 参数不正确仅发生在，仅超声机画面，且 SupportRtc = false 的情况下
    // 补充，无需判定 SupportRtc，因为 SupportRtc 为 true 时，也会出现参数错乱的情况
    // http://test.ius.plus:88/mantis2/view.php?id=14598
    // if (device.videoDeviceInfos!.length == 1 && !device.supportRtc) {
    if (device.videoDeviceInfos!.length == 1) {
      if (mainView.outputWidth == size.width.toInt() &&
          mainView.outputHeight == size.height.toInt()) {
        return; // 相等则不处理
      }
      mainView.outputWidth = size.width.toInt();
      mainView.outputHeight = size.height.toInt();
      if (mainView.liveData != null) {
        mainView.liveData!.width = size.width.toInt();
        mainView.liveData!.height = size.height.toInt();
      }

      /// 需要发送虚拟【加入房间】事件
      Get.find<IRtmpMockRtcManager>().updateDevice(LiveConsultationMember(
          id: device.id,
          videoDeviceInfos: [mainView],
          memberType: device.memberType,
          mergedChannel: device.mergedChannel,
          mergedVideoOutputHeight: size.width.toInt(),
          mergedVideoOutputWidth: size.height.toInt(),
          mute: device.mute,
          videoOpend: device.videoOpend));
      print("修正接口参数，修正为：$size");
    }
  }

  /// 处理视频断流回调
  void _handleVideoLostCallback(_, bool isLost) {
    print('视频断流回调 isLost:$isLost');

    /// 将设备 channel 置空
    controller.state.deviceDesktopChannel = null;
    controller.loadingController.showRetryButton();
  }

  Size selectResolution(Size size) {
    final width = size.width;
    final height = size.height;
    if (width <= 640 && height <= 480) {
      return const Size(640, 480);
    } else if (width <= 960 && height <= 544) {
      return const Size(960, 540);
    } else if (width <= 960 && height <= 720) {
      return const Size(960, 720);
    } else if (width <= 1280 && height <= 720) {
      return const Size(1280, 720);
    } else {
      return const Size(1920, 1080);
    }
  }

  void _onChannelRemoved(Object s, IPlayChannel channel) {
    channel as BasePlayChannel;
    channel.onVideoInfo.removeListener(_handleVideoInfoCallback);
    channel.onVideoLost.removeListener(_handleVideoLostCallback);
    var desktopDeviceInfo = state.desktopDeviceInfo;
    var userId = channel.member.userId ?? '';
    if (cameraDeviceInfo != null && cameraDeviceInfo!.videoDeviceId == userId) {
      state.deviceCameraChannel = null;
    } else if (desktopDeviceInfo != null &&
        desktopDeviceInfo.videoDeviceId == userId) {
      state.deviceDesktopChannel = null;
      controller.loadingController.startLoading();
    }
    if (state.playChannels.containsKey(userId)) {
      state.playChannels.update(userId, (value) {
        value.channel = null;
        value.started = false;
        return value;
      });
    } else {
      logger.i('channel remove userId:$userId');
    }
  }

  void _onExited(Object sender, void e) {}

  void _enter() {
    var liveConsultation = state.liveConsultation;
    var userCode = liveConsultation.initiatorCode.isNotNullOrEmpty
        ? liveConsultation.initiatorCode
        : liveConsultation.userCode;
    _room.loadLocalMember(LocalMemberParams(
      userId: userCode ?? '',
      userSig: liveConsultation.userSign,
      extParams: {},
    ));
    _room.enter();
    Get.find<IRtmpMockRtcManager>().handleEnterRoom();
  }

  Future<bool> _checkPermission() async {
    bool checkResult = true;
    if (!kIsMobile) {
      return checkResult;
    }
    var cameraStatus = await Permission.camera.status;
    if (!cameraStatus.isGranted) {
      // 摄像头权限未授予，请求权限
      var result = await Permission.camera.request();
      if (!result.isGranted) {
        checkResult = false;
      }
    }
    // 检查麦克风权限
    var microphoneStatus = await Permission.microphone.status;
    if (!microphoneStatus.isGranted) {
      // 麦克风权限未授予，请求权限
      var result = await Permission.microphone.request();
      if (!result.isGranted) {
        checkResult = false;
      }
    }
    // 检查扬声器权限
    var speakerStatus = await Permission.speech.status;
    if (!speakerStatus.isGranted) {
      // 扬声器权限未授予，请求权限
      var result = await Permission.speech.request();
      if (!result.isGranted) {
        // 用户已授予扬声器权限
        checkResult = false;
      }
    }
    return checkResult;
  }

  ///初始化超声机设备信息
  void _initDeviceInfo() {
    var deviceCode = controller.state.consultationDetail.deviceCode;
    if (controller.state.memberStatus.containsKey(deviceCode)) {
      var member = controller.state.memberStatus.values
          .firstWhere((element) => element.memberType == LiveMemberEnum.Device);
      var videoDeviceInfos = member.videoDeviceInfos ?? [];
      cameraDeviceInfo = videoDeviceInfos.firstWhereOrNull((element) =>
          element.videoDeviceSourceType == VideoDeviceSourceTypeEnum.Camera);
      state.desktopDeviceInfo = videoDeviceInfos.firstWhereOrNull((element) =>
          element.videoDeviceSourceType == VideoDeviceSourceTypeEnum.Desktop);
    }
  }
}
