import 'package:fis_jsonrpc/services/index.dart';
import 'package:fis_lib_media_rt/implementations/nt_rtmp/rtc_adapter.dart';
import 'package:fis_lib_media_rt/implementations/nt_rtmp/models.dart';
import 'package:fis_lib_media_rt/config.dart';
import 'package:flyinsono/architecture/states/states.dart';
import 'package:get/get.dart';

import 'base_manager.dart';
import 'interfaces/rtmp_mock_rtc.dart';

class RtmpMockRtcManager extends BaseManager implements IRtmpMockRtcManager {
  List<LiveConsultationMember>? _originMembers;

  bool get isRtmpMode =>
      FRTMediaConfig.serviceType == FRealTimeMediaServiceType.ntRtmp;

  @override
  void handleRemoteAccept(LiveConsultatioAccepterInfo accepter) {
    if (!isRtmpMode) return;

    final member = _originMembers?.firstWhereOrNull((e) => e.id == accepter.id);

    RtmpLiveInfo? liveInfo;
    if (member != null) {
      final liveData = member.liveData!;
      liveInfo = RtmpLiveInfo(
        flvUrl: liveData.httpPullUrl!,
        rtmpUrl: liveData.rtmpPullUrl!,
        height: liveData.height,
        width: liveData.width,
      );
    }

    final data = RtmpMemberInfo(
      id: accepter.id!,
      liveInfo: liveInfo,
      deviceInfoList: null,
    );
    NTRtmp2RtcAdapter.adapter.remoteMemberJoineEvent.emit(this, data);
  }

  @override
  void handleRemoteJoinIn(LiveConsultationJoinerInfo joiner) {
    if (isRtmpMode) {
      final liveData = joiner.liveData!;
      final data = RtmpMemberInfo(
        id: joiner.id!,
        liveInfo: RtmpLiveInfo(
          flvUrl: liveData.httpPullUrl!,
          rtmpUrl: liveData.rtmpPullUrl!,
          height: liveData.height,
          width: liveData.width,
        ),
        deviceInfoList: null,
      );
      _emitMemberJoin(data);
    }
  }

  @override
  void handleRemoteLeave(LiveConsultationLeaverInfo joiner) {
    if (isRtmpMode) {
      final id = joiner.id!;
      NTRtmp2RtcAdapter.adapter.remoteMemberLeaveEvent.emit(this, id);
    }
  }

  @override
  void storeOriginData(List<LiveConsultationMember>? members) {
    if (!isRtmpMode) return;

    if (members == null || members.isEmpty) return;

    _originMembers = List.from(members);

    final localIndex =
        _originMembers!.indexWhere((e) => e.id == Store.user.code);
    if (localIndex < 0) return;

    // 本地成员
    final member = _originMembers![localIndex];
    _originMembers!.removeAt(localIndex);

    final liveData = member.liveData!;
    NTRtmp2RtcAdapter.adapter.localMemberInfo = RtmpMemberInfo(
      id: member.id!,
      liveInfo: RtmpLiveInfo(
        pushUrl: liveData.rtmpPushUrl,
        flvUrl: '',
        rtmpUrl: '',
        height: 0,
        width: 0,
      ),
    );
  }

  @override
  void updateDevice(LiveConsultationMember device) {
    if (!isRtmpMode) return;
    _handleDeviceLeave();

    /// 将设备更新为新设备
    final deviceIndex = _originMembers!
        .indexWhere((e) => e.memberType == LiveMemberEnum.Device);
    if (deviceIndex >= 0) {
      _originMembers![deviceIndex] = device;
    }
    _handleDeviceJoin(device);
  }

  @override
  void handleEnterRoom() {
    if (!isRtmpMode) return;

    final members = _originMembers;
    if (members == null || members.isEmpty) return;

    final userMembers =
        members.where((e) => e.memberType == LiveMemberEnum.User);
    for (final member in userMembers) {
      _emitExistRemoteJoin(member);
    }

    // 设备成员
    final deviceMember =
        members.firstWhereOrNull((e) => e.memberType == LiveMemberEnum.Device);
    if (deviceMember != null) {
      _handleDeviceJoin(deviceMember);
    }
  }

  void handleRemoteMuteVideo(String id, bool isMute) {
    NTRtmp2RtcAdapter.adapter.mmberMuteVideoEvent.emit(
      this,
      RtmpSetMuteEventArgs(userId: id, isMute: isMute),
    );
  }

  void handleRemoteMuteAudio(String id, bool isMute) {
    NTRtmp2RtcAdapter.adapter.mmberMuteAudioEvent.emit(
      this,
      RtmpSetMuteEventArgs(userId: id, isMute: isMute),
    );
  }

  void _emitExistRemoteJoin(LiveConsultationMember member) {
    final liveData = member.liveData!;
    final data = RtmpMemberInfo(
      id: member.id!,
      liveInfo: RtmpLiveInfo(
        rtmpUrl: liveData.rtmpPullUrl!,
        flvUrl: liveData.httpPullUrl!,
        height: liveData.height,
        width: liveData.width,
      ),
      deviceInfoList: null,
    );
    _emitMemberJoin(data);
  }

  void _handleDeviceJoin(LiveConsultationMember member) {
    if (member.videoDeviceInfos == null || member.videoDeviceInfos!.isEmpty) {
      return;
    }

    // 如果只有一个设备
    if (member.videoDeviceInfos!.length == 1) {
      final device = member.videoDeviceInfos!.first;
      final data = RtmpMemberInfo(
        id: device.videoDeviceId!, // 进入WebRTC时的用户名
        deviceInfoList: [_convertDeviceLiveInfo(member, device)],
      );
      _emitMemberJoin(data);
    } else {
      // 如果有多个设备，先找出主画面，再过滤出摄像头数组
      final mainview = member.videoDeviceInfos!.first;
      final subViewList = member.videoDeviceInfos!
          .where((e) =>
              e.videoDeviceSourceType == VideoDeviceSourceTypeEnum.Camera)
          .toList();
      final mainViewData = RtmpMemberInfo(
        id: mainview.videoDeviceId!, // 进入WebRTC时的用户名
        deviceInfoList:
            _convertDeviceLiveInfoList(member, member.videoDeviceInfos!),
      );
      _emitMemberJoin(mainViewData);
      for (var device in subViewList) {
        // 一个设备一个成员，设备成员↔设备Channel一对一
        final data = RtmpMemberInfo(
          id: device.videoDeviceId!, // 进入WebRTC时的用户名
          deviceInfoList: [_convertDeviceLiveInfo(member, device)],
        );
        _emitMemberJoin(data);
      }
    }
  }

  void _handleDeviceLeave() {
    /// 将当前存在的设备都退出房间
    final deviceIndex = _originMembers!
        .indexWhere((e) => e.memberType == LiveMemberEnum.Device);
    if (deviceIndex < 0) return;
    final member = _originMembers![deviceIndex];

    for (VideoDeviceOutputInfo device in member.videoDeviceInfos!) {
      NTRtmp2RtcAdapter.adapter.remoteMemberLeaveEvent
          .emit(this, device.videoDeviceId!);
    }
  }

  void _emitMemberJoin(RtmpMemberInfo member) {
    NTRtmp2RtcAdapter.adapter.remoteMemberJoineEvent.emit(this, member);

    Future.delayed(const Duration(milliseconds: 100), () {
      handleRemoteMuteVideo(member.id, true);
      handleRemoteMuteAudio(member.id, true);
    });
  }

  DeviceRtmpLiveInfo _convertDeviceLiveInfo(
    LiveConsultationMember member,
    VideoDeviceOutputInfo device,
  ) {
    return DeviceRtmpLiveInfo(
      type: DeviceTypeEnum.values[device.videoDeviceSourceType.index],
      rtmpUrl: device.liveData!.rtmpPullUrl!,
      flvUrl: device.liveData!.httpPullUrl!,
      height: device.outputHeight,
      width: device.outputWidth,
      isMerge: member.mergedChannel,
      isOldPlatform: member.isOldPlatform,
      mergeWidth: member.mergedVideoOutputWidth,
      mergeHeight: member.mergedVideoOutputHeight,
    );
  }

  List<DeviceRtmpLiveInfo> _convertDeviceLiveInfoList(
    LiveConsultationMember member,
    List<VideoDeviceOutputInfo> devices,
  ) {
    return devices.map((e) => _convertDeviceLiveInfo(member, e)).toList();
  }
}
