import 'dart:math';

import 'package:fis_common/index.dart';
import 'package:fis_common/logger/logger.dart';
import 'package:fis_jsonrpc/rpc.dart';
import 'package:flyinsono/architecture/states/states.dart';
import 'package:flyinsono/managers/interfaces/entities/consultation_member.dart';
import 'package:flyinsono/managers/interfaces/entities/live_course_membel.dart';
import 'package:flyinsono/managers/interfaces/flyinsono_college.dart';
import 'package:flyinsono/pages/live_course/index.dart';
import 'package:fis_lib_media_rt/fis_lib_media_rt.dart';
import 'package:flyinsono/rpc.dart';
import 'package:get/get.dart';
import 'package:tencent_trtc_cloud/trtc_cloud.dart';
import 'package:tencent_trtc_cloud/tx_device_manager.dart';
import 'package:flyinsono/architecture/services/entity/hardware_setting.dart';

class MediaController {
  final flyinsonoCollegeManager = Get.find<IFlyinsonoCollegeManager>();
  late final LiveCourseController controller;
  late final BaseRoom _room;
  bool _entered = false;
  IPublisher? _publisher;
  IPlayer? _player;
  LiveCourseState get state => controller.state;

  MediaController(LiveCourseController c) {
    controller = c;
  }

  void init() {
    ///小班化成员进入房间
    _initRoom();

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

  ///开始屏幕采集
  void startScreenCapture() {
    var liveCourse = state.liveCourse!;
    _room.startScreenCapture(liveCourse.rtcScreenSharingChannel!.userCode!,
        liveCourse.rtcScreenSharingChannel!.userSign!);
  }

  ///设置静音
  void setAudioMute(bool isMute, String userCode) {
    var member = state.liveCourseMembers
        .firstWhereOrNull((element) => element.id == userCode);
    if (member != null) {
      if (member.channelInfos?.isNotEmpty ?? false) {
        member.channelInfos!.first.setAudioMute(isMute);
      }
      member.mute = isMute;
    }
  }

  ///结束屏幕采集
  void stopScreenCapture() {
    _room.stopScreenCapture();
  }

  void dispose() {
    _room.exit();
  }

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

  void _enter() {
    var liveConsultation = state.liveCourse;
    _room.loadLocalMember(LocalMemberParams(
      userId: Store.user.code,
      userSig: liveConsultation!.userSign,
      extParams: {},
    ));
    _room.enter();
  }

  void _onExited(Object sender, void e) {}

  void _onEntered(Object sender, void e) {
    _initPublisher();
    _initPlayer();
    if (!_entered) {
      _entered = true;
      _startLocal();
    }
  }

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

  void _initPublisher() {
    if (_publisher != null) return;
    _publisher = _room.createPublisher();
    state.liveCourseMembers
        .firstWhere((element) => element.id == Store.user.code)
        .channelInfos = [_publisher!.channels.first];
    controller.memberChange.emit(this, null);
  }

  void _onChannelRemoved(Object s, IPlayChannel channel) {
    channel as BasePlayChannel;
    var userId = channel.member.userId;
    if (state.liveCourseMembers.any((element) => element.id == userId)) {
      var member =
          state.liveCourseMembers.firstWhere((element) => element.id == userId);
      member.channelInfos = null;
      member.memberStatus = MemberStatus.Left;
      if (member.memberType == LiveMemberEnum.Device) {
        state.mainChannel = null;
      }
    } else {
      logger.i('channel remove userId:$userId');
    }
    controller.memberChange.emit(this, null);
  }

  void _onChannelAdded(Object s, IPlayChannel channel) async {
    channel as BasePlayChannel;
    var memberId = channel.member.userId ?? '';
    var deviceMember = state.liveCourseMembers.firstWhereOrNull(
        (element) => element.memberType == LiveMemberEnum.Device);
    var shareScreenId = state.liveCourse!.rtcScreenSharingChannel?.userCode;
    var idInfos = memberId.split('_');

    ///屏幕分享
    if (shareScreenId == memberId) {
      if (!state.isLocalDesktopShare) {
        state.mainChannel = channel;
      }
    } else if (state.liveCourseMembers.any((e) => e.id == memberId)) {
      //已存在的成员
      state.liveCourseMembers
          .firstWhere((element) => element.id == memberId)
          .channelInfos = [channel];
      state.mainChannel =
          channel; // FIXME !!! 此处未判断是超声机，可能有极大风险存在问题，例如其他人员也加入TRTC房间，会占领主画面
    } else {
      //成员不存在，但是有新的channel进来
      if (deviceMember != null) {
        ///已存在的超声机中有channel能匹配上，则是超声机画面或扫查手法画面（培训无需考虑扫查手法）
        var target = deviceMember.videoDeviceInfos!.firstWhereOrNull(
          (element) =>
              element.videoDeviceId == memberId &&
              element.videoDeviceSourceType ==
                  VideoDeviceSourceTypeEnum.Desktop,
        );
        if (target != null) {
          if (deviceMember.channelInfos == null) {
            deviceMember.channelInfos = [channel];
          } else {
            deviceMember.channelInfos!.add(channel);
          }
          state.mainChannel = channel;
          state.isLoadingDevice = false;
          logger.i('device join success');
        }
      } else if (memberId.contains('_') && idInfos.length == 2) {
        ///新版本超声机桌面：唯一码_唯一码，摄像头：唯一码_Camera...
        state.isLoadingDevice = true;
        if (idInfos[0] == idInfos[1]) {
          ///前后相同则是超声机画面
          state.liveCourseMembers.add(
            FLiveCourseMember(
              memberType: LiveMemberEnum.Device,
              channelInfos: [channel],
            ),
          );
          state.mainChannel = channel;
          logger.i('device join success,but no menmer');
        }
      } else {
        ///老版本超声机的Id没有特殊的标志，需MemberListenerController中_onJoinLiveCourse处理
        state.liveCourseMembers.add(
          FLiveCourseMember(
            id: memberId,
            memberType: LiveMemberEnum.placeHolder_0,
            channelInfos: [channel],
          ).fixMergedVideoOutputSize(),
        );
      }
    }
    controller.memberChange.emit(this, null);
    channel.readyStateChanged.addListener((sender, e) {
      if (e) {
        channel.play();
      }
    });
  }

  ///开启本地推流
  void _startLocal() async {
    // 获取缓存的推荐硬件设置
    HardwareSetting hardwareSetting = HardwareSetting.ins;
    final String idealCameraName = hardwareSetting.idealWebVideoInputDeviceName;
    final String idealMicrophoneName =
        hardwareSetting.idealWebAudioInputDeviceName;
    print(
        "⭐⭐ 预设硬件配置 idealCameraName: $idealCameraName idealMicrophoneName: $idealMicrophoneName");
    // 这里缺个事件，收到通知后可设置分辨率
    // 这里是TRTC SDK设计原因，所以要先播放才能改分辨率，是否魔改以后再说
    _publisher!.setProfile(PublisherProfile(
        resolutionMode: ResolutionMode.landscape,
        resolution: Resolutions.sd_480p,
        frameRate: 10,
        idealCameraName: idealCameraName,
        idealMicrophoneName: idealMicrophoneName));
    _publisher!.channels.first.readyStateChanged.addListener((sender, e) async {
      if (e) {
        await _publisher!.startLocal();
        if (state.isTeacher) {
          _startLocalWindowPublish();
        }
      }
    });
  }

  ///开启本地推流
  Future<void> _startLocalWindowPublish() async {
    if (FPlatform.isWindows || FPlatform.isMacOS) {
      var teacherCode = state.courseDetail!.teacherCode;
      var teachMember = state.liveCourseMembers
          .firstWhereOrNull((element) => element.id == teacherCode);
      if (teachMember != null) {
        String? deviceName;
        try {
          HardwareSetting hardwareSetting = HardwareSetting.ins;
          deviceName = hardwareSetting.idealWebAudioInputDeviceName;
        } catch (e) {
          logger.e('LiveCourseController _startLocalWindowPublish ex:', e);
        }
        var courseChannel = state.liveCourse!.courseChannel;
        if (courseChannel != null) {
          var pushUrl = courseChannel.rtmpPushUrl!;
          rpc.platform.startTrainningPush(
            pushUrl,
            deviceName ?? "",
            TranningPushEnum.Window,
          );
        }
      }
    }
  }
}
