import 'dart:async';
import 'dart:collection';
import 'dart:io';
import 'package:fis_common/index.dart';
import 'package:fis_common/logger/logger.dart';
import 'package:fis_lib_media_rt/implementations/trtc/channel.dart';
import 'package:fis_lib_media_rt/implementations/trtc/resolutions.dart';
import 'package:fis_lib_media_rt/implementations/trtc/room.dart';
import 'package:fis_lib_media_rt/interface/channel.dart';
import 'package:fis_lib_media_rt/interface/enums.dart';
import 'package:flutter/foundation.dart';
import 'package:tencent_trtc_cloud/trtc_cloud_def.dart';
import 'package:tencent_trtc_cloud/trtc_cloud_listener.dart';
import 'package:tencent_trtc_cloud/tx_device_manager.dart';

import '../../base/publisher.dart';
import '../../interface/publisher.dart';
import 'client_getter_mixin.dart';

class TrtcPublisher extends BasePublisher with TrtcClientGetterMixin {
  // ignore: non_constant_identifier_names
  static final Map<Resolutions, BitrateRange> C_BITRATE_RANGE = {
    Resolutions.sd_480p: BitrateRange(200, 1000, 800),
    Resolutions.hd_720p: BitrateRange(500, 2000, 1250),
    Resolutions.fhd_1080p: BitrateRange(800, 3000, 1900),
  };

  final isOpenMic = true;
  final isOpenCamera = true;
  final quality = TRTCCloudDef.TRTC_AUDIO_QUALITY_DEFAULT;
  final isFrontCamera = true;
  final localViewId = 0;
  TrtcPublishChannel? get _channel =>
      room.localMember.channels.first as TrtcPublishChannel;

  PublisherProfile? _profile;

  TrtcPublisher({required super.room}) {
    _trtcRoom = room as TrtcRoom;
    _buildPreviewChannel();
  }

  late TrtcRoom _trtcRoom;

  @override
  UnmodifiableListView<IPublishChannel> get channels => UnmodifiableListView(
      room.localMember.channels.map((e) => e as IPublishChannel));

  @override
  Future<void> startLocal() async {
    try {
      // if (Platform.isIOS) {
      //   try {
      //     client.setGSensorMode(2);
      //     final TXDeviceManager deviceManager = client.getDeviceManager();
      //     deviceManager.setSystemVolumeType(1);
      //   } catch (e) {
      //     logger.e('TrtcPublisher startLocal', e);
      //   }
      // }
      // _buildPreviewChannel();
      if (_channel!.viewId > -1) {
        await client.startLocalPreview(true, _channel!.viewId);
        print('🎉Camera Preview Started');
      }
      if (kIsWeb) {
        _trtcRoom.events.once(
          TRTCCloudListener.onStreamPublish,
          (param) async {
            if (param == 0) {
              await client
                  .startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_DEFAULT);
              try {
                final TXDeviceManager deviceManager = client.getDeviceManager();
                if (_profile!.idealCameraName != null) {
                  final List<dynamic>? cameras =
                      await deviceManager.getDevicesList(2);
                  if (cameras != null && cameras.isNotEmpty) {
                    for (var camera in cameras) {
                      if (camera['label'] == _profile!.idealCameraName) {
                        deviceManager.setCurrentDevice(2, camera['deviceId']);
                      }
                    }
                  }
                }
                if (_profile!.idealMicrophoneName != null) {
                  final List<dynamic>? microphones =
                      await deviceManager.getDevicesList(0);
                  if (microphones != null && microphones.isNotEmpty) {
                    for (var microphone in microphones) {
                      if (microphone['label'] ==
                          _profile!.idealMicrophoneName) {
                        deviceManager.setCurrentDevice(
                            0, microphone['deviceId']);
                      }
                    }
                  }
                }
              } catch (e) {
                logger.e("[TrtcPublisher] set ideal device error", e);
              }
            }
          },
        );
      } else {
        await client.startLocalAudio(quality);
      }
      _channel!.isPreviewing = true;
    } catch (e) {
      logger.e("[TrtcPublisher] start local preview error", e);
    }
  }

  @override
  Future<void> stopLocal() async {
    try {
      await client.stopLocalAudio();
      await client.stopLocalPreview();
      _channel!.isPreviewing = false;
      // _removePreviewChannel();
    } catch (e) {
      logger.e("[TrtcPublisher] stop local preview error", e);
    }
  }

  @override
  Future<void> setProfile(PublisherProfile profile) async {
    if (_updateProfileCache(profile) == false) {
      // 配置未变更的，直接返回
      return;
    }
    final currProfile = _profile!;
    final resolution = TrtcResolutions.convert(currProfile.resolution);
    final bitrate = currProfile.bitrate ??
        C_BITRATE_RANGE[currProfile.resolution]?.defaultBitrate ??
        900;

    // _buildPreviewChannel();
    _channel!.videoEncParam = TRTCVideoEncParam(
      videoFps: currProfile.frameRate,
      videoResolution: resolution,
      videoBitrate: bitrate,
      videoResolutionMode: currProfile.resolutionMode.index,
    );

    client.setVideoEncoderParam(_channel!.videoEncParam!);
    print('✨Changed Resolution to 480P');
  }

  void _buildPreviewChannel() {
    if (channels.isEmpty) {
      final channel = TrtcPublishChannel(member: room.localMember);
      room.localMember.addChannel(channel);
    }
  }

  void _removePreviewChannel() {
    if (channels.isNotEmpty) {
      room.localMember.clearChannels(); //TODO: 目前只有主画面的
    }
  }

  /// 比较和更新Profile
  bool _updateProfileCache(PublisherProfile newProfile) {
    bool isSame = true;
    if (_profile != null) {
      final oldProfile = _profile!;
      isSame = isSame && newProfile.resolution == oldProfile.resolution;
      isSame = isSame && newProfile.frameRate == oldProfile.frameRate;
      isSame = isSame && newProfile.bitrate == oldProfile.bitrate;
      isSame = isSame && newProfile.resolutionMode == oldProfile.resolutionMode;
      isSame =
          isSame && newProfile.idealCameraName == oldProfile.idealCameraName;
      isSame = isSame &&
          newProfile.idealMicrophoneName == oldProfile.idealMicrophoneName;
    } else {
      isSame = false;
    }
    if (isSame == false) {
      _profile = newProfile;
    }
    return !isSame;
  }
}
