import 'dart:typed_data';

import 'package:fis_common/index.dart';
import 'package:fis_common/logger/logger.dart';
import 'package:fis_i18n/i18n.dart';
import 'package:fis_jsonrpc/rpc.dart';
import 'package:fis_lib_media_rt/interface/index.dart';
import 'package:fis_measure/utils/prompt_box.dart';
import 'package:fis_ui/values.dart';
import 'package:flutter/material.dart';
import 'package:flyinsono/architecture/states/states.dart';
import 'package:flyinsono/managers/interfaces/appointment_consultation.dart';
import 'package:flyinsono/notifications/handlers/consulation/upload_consultation_data_handler.dart';
import 'package:flyinsono/rpc.dart';
import 'package:flyinsono/views/desktop/real_time_consultation/live_consultation/controller.dart';
import 'package:flyinsono/views/desktop/real_time_consultation/live_consultation/state.dart';
import 'package:flyinsono/views/desktop/real_time_consultation/live_consultation/utils/image_conpress/index.dart';
import 'package:get/get.dart';
import 'package:vid/us/vid_us_image.dart';
import 'package:vid/us/vid_us_image_data.dart';

class RecordingController extends GetxController {
  LiveConsultationController controller;
  Duration _recordingDurstion = Duration(seconds: 0);
  final appointmentConsultationManager = Get.find<IAppointmentConsultation>();

  /// 主画面key
  GlobalKey mainUSViewKey = GlobalKey();
  RecordingController(this.controller);

  /// 是否需要裁剪
  bool get isNeedCrop => controller.state.isNeedCropDeviceDesktop;

  /// 超声机主画面裁切区域
  Rect get mainUSViewCropRect => controller.state.mainViewRectInMergedMode;

  LiveConsulationState get state => controller.state;
  late UploadConsultationDataHandler uploadConsultationDataHandler;

  void dispose() {
    super.dispose();
    uploadConsultationDataHandler.unsubscribe(handleUploadConsultation);
  }

  void handleUploadConsultation(_) {
    _updateCaptureResultList();
  }

  /// 截取一帧 vid
  void captureOneFrame() async {
    if (state.isVidFileCapturing) {
      PromptBox.toast(i18nBook.remedical.ImageProcessing.t);
      return;
    }
    final IPlayChannel? deviceChannel = state.deviceDesktopChannel;
    if (deviceChannel == null) {
      PromptBox.toast(i18nBook.realTimeConsultation.noUsChannel.t);
    } else {
      final capturer = deviceChannel.createCapture();
      state.isVidFileCapturing = true;
      state.isVidFileCapturingByRecording = false;
      if (kIsMobile) {
        Size frameSize = _countChannelSize();
        await capturer.initCapturer(
            width: frameSize.width.toInt(),
            height: frameSize.height.toInt(),
            isNeedCrop: isNeedCrop,
            cropArea: mainUSViewCropRect);
      } else {
        await capturer.initCapturer(
            isNeedCrop: isNeedCrop, cropArea: mainUSViewCropRect);
      }
      try {
        VidUsImageData vidUsImageData = await capturer.captureFrame();
        state.isVidFileCapturing = false;
        await _updateConsultationFilesInfoAsync(vidUsImageData, true);
      } catch (e) {
        print(e);
        PromptBox.toast(i18nBook.realTimeConsultation.captureFailed.t);
        state.isVidFileCapturing = false;
      }
    }
  }

  ///结束录制
  void endRecording() async {
    final IPlayChannel? deviceChannel = state.deviceDesktopChannel;
    if (deviceChannel == null) {
      PromptBox.toast(i18nBook.realTimeConsultation.noUsChannel.t);
    } else {
      final capturer = deviceChannel.createCapture();
      if (!state.isVidCapturerRecording) return;
      state.isVidCapturerRecording = false;
      state.isVidFileCapturing = true;
      state.isVidFileCapturingByRecording = true;
      try {
        VidUsImageData vidUsImageData = await capturer.stopRecord();
        state.isVidFileCapturing = false;
        await _updateConsultationFilesInfoAsync(vidUsImageData, false);
      } catch (e) {
        state.isVidFileCapturing = false;
        PromptBox.toast(i18nBook.realTimeConsultation.recordFailed.t);
      }
    }
  }

  ///开启全程录制
  void fullRecordingOperation() async {
    if (state.isFullRecording) {
      //暂停录制
      if (!state.isFullRecordingPause) {
        await rpc.platform.pauseRecording(true);
        state.isFullRecordingPause = true;
        _recordingDurstion =
            DateTime.now().difference(state.vidCapturerStartTime);
        return;
      } else {
        //开启录制
        state.vidCapturerStartTime =
            DateTime.now().subtract(_recordingDurstion);
        rpc.platform.pauseRecording(false);
        state.isFullRecordingPause = false;
        return;
      }
    }
    var consultationDetail = state.consultationDetail;
    var applyhospitalName = consultationDetail.applyOrganizationName;
    var applyPatient = consultationDetail.patientName;
    applyPatient = applyPatient!.replaceAll("*", "x");
    var consultationTitle = "$applyhospitalName-$applyPatient";
    await rpc.platform
        .startRecording(consultationTitle, "YourCurrentMicDeviceId");
    state.isFullRecording = true;
    state.vidCapturerStartTime = DateTime.now();
  }

  void initCaptureImageList() async {
    /// 等待 1s, 等待 consultationCode 赋值
    await Future.delayed(Duration(milliseconds: 1000));
    await _updateCaptureResultList();
    update(['capture_image_list']);
    uploadConsultationDataHandler = Get.find<UploadConsultationDataHandler>();
    uploadConsultationDataHandler.subscribe(handleUploadConsultation);
  }

  ///开启录制
  void startRecording() async {
    if (state.isVidFileCapturing) {
      PromptBox.toast(i18nBook.realTimeConsultation.processingImage.t);
      return;
    }
    final IPlayChannel? deviceChannel = state.deviceDesktopChannel;
    if (deviceChannel == null) {
      PromptBox.toast(i18nBook.realTimeConsultation.noUsChannel.t);
    } else {
      final capturer = deviceChannel.createCapture();
      if (state.isVidCapturerRecording) return;
      state.isVidCapturerRecording = true;
      if (kIsMobile) {
        Size frameSize = _countChannelSize();
        await capturer.initCapturer(
            width: frameSize.width.toInt(),
            height: frameSize.height.toInt(),
            isNeedCrop: isNeedCrop,
            cropArea: mainUSViewCropRect);
      } else {
        await capturer.initCapturer(
            isNeedCrop: isNeedCrop, cropArea: mainUSViewCropRect);
      }
      capturer.startRecord();
      state.vidCapturerStartTime = DateTime.now();
    }
  }

  ///结束全程录制
  void stopFullRecording() async {
    try {
      if (FPlatform.isWindows || FPlatform.isMacOS) {
        await rpc.platform.stopRecording();
        state.isFullRecording = false;
        state.isFullRecordingPause = false;
      }
    } catch (e) {
      logger.e('RecordingController stopFullRecording ex:', e);
    }
  }

  /// 压缩 vid
  Future<VidUsImageData> _compressVid(VidUsImageData vidUsImageData) async {
    final int imageCount = vidUsImageData.imageCount;
    final double fps = vidUsImageData.probe.frameRate;
    final VidUsImageData compressedImageData =
        VidUsImageData.empty(imageCount, VidUsImageFormat.Jpeg);
    for (int i = 0; i < imageCount; i++) {
      final VidUsImage vidUsImage = vidUsImageData.getImage(i);
      final Uint8List compressedJpegBytes =
          await compressImage(vidUsImage.imageData, 50, 1080);
      compressedImageData.addJpegImage(
          compressedJpegBytes, vidUsImage.width, vidUsImage.height);
    }
    compressedImageData.setThirdPartFPS(fps.toInt());
    return compressedImageData;
  }

  Size _countChannelSize() {
    final mainUSView = mainUSViewKey.currentContext?.findRenderObject();
    if (mainUSView != null) {
      final mainUSViewSize = mainUSView.paintBounds.size;
      final pixelRatio = Get.pixelRatio;
      final displaySize = Size(mainUSViewSize.width * pixelRatio,
          mainUSViewSize.height * pixelRatio);
      return displaySize;
    }
    return Size(1920, 1080);
  }

  /// 传入 jpegBytes，绘制到canvas生成缩略图，返回 jpegBytes
  Future<Uint8List> _generatePreviewImage(Uint8List jpegBytes) async {
    //// Web 端需要自己扩展压缩方法
    var result = await compressImage(jpegBytes, 80, 200);
    return result;
  }

  /// 更新捕获结果列表
  Future<void> _updateCaptureResultList() async {
    if (state.captureImageUploadingCount > 0) return;
    state.captureImageUploadOnceSum = 0;
    final List<ConsultationImagesDTO> consultationImageFolders =
        await appointmentConsultationManager.getConsultationImages(
            state.consultationDetail.consultationCode ?? '');
    if (consultationImageFolders.isEmpty) return;
    List<ConsultationFileDTO> captureImageList = [];
    for (var consultationImageFolder in consultationImageFolders) {
      if (consultationImageFolder.screenshotList != null) {
        captureImageList.addAll(consultationImageFolder.screenshotList!);
      }
    }
    state.captureImageList = captureImageList;
  }

  /// 上传录制的 vid
  Future<bool> _updateConsultationFilesInfoAsync(
      VidUsImageData vidUsImageData, bool isSingle) async {
    if (vidUsImageData.imageCount <= 0) {
      if (isSingle) {
        PromptBox.toast(i18nBook.realTimeConsultation.captureFailed.t);
      } else {
        PromptBox.toast(i18nBook.realTimeConsultation.recordFailed.t);
      }
      return false;
    }
    if (!state.isShowCaptureImageList) {
      state.isShowCaptureImageList = true;
    }
    state.captureImageUploadingCount++;
    state.captureImageUploadOnceSum++;
    final String suffix = DateTime.now().millisecondsSinceEpoch.toString();
    final String sourceFileName = "$suffix.vid";
    final String previewFileName = "$suffix-preview.jpg";
    final String coverFileName = "$suffix-cover.jpg";

    /// 移动端需要对 vidUsImageData 进行压缩，生成新的压缩后的 vidUsImageData
    VidUsImageData compressedImageData =
        kIsMobile ? await _compressVid(vidUsImageData) : vidUsImageData;
    final String sourceUrl = await rpc.storage
            .uploadUint8List(compressedImageData.flush(), sourceFileName) ??
        '';
    print('sourceUrl: $sourceUrl');
    Uint8List coverImageData = vidUsImageData.getImage(0).imageData;
    final String coverUrl =
        await rpc.storage.uploadUint8List(coverImageData, coverFileName) ?? '';
    print('coverUrl: $coverUrl');
    final previewImage =
        await _generatePreviewImage(vidUsImageData.getImage(0).imageData);
    final String previewUrl =
        await rpc.storage.uploadUint8List(previewImage, previewFileName) ?? '';
    print('previewUrl: $previewUrl');
    if (previewUrl == '' || coverUrl == '' || sourceUrl == '') {
      state.captureImageUploadingCount--;
      if (sourceUrl == '') {
        PromptBox.toast(i18nBook.common.uploadFail.t);
        return false;
      }
      if (isSingle) {
        PromptBox.toast(i18nBook.realTimeConsultation.captureFailed.t);
      } else {
        PromptBox.toast(i18nBook.realTimeConsultation.recordFailed.t);
      }
      return false;
    }
    final UpdateConsultationFilesInfoRequest request =
        UpdateConsultationFilesInfoRequest(
            token: Store.user.token,
            consultationCode: state.liveConsultation.consultationCode ?? '',
            fileInfos: [
          ConsultationFileBaseDTO(
              coverImageUrl: coverUrl,
              previewImageUrl: previewUrl,
              sourceUrl: sourceUrl,
              fileDataType: isSingle
                  ? RemedicalFileDataTypeEnum.ThirdVidSingle
                  : RemedicalFileDataTypeEnum.ThirdVidMovie)
        ]);
    try {
      bool result =
          await rpc.liveConsultation.updateConsultationFilesInfoAsync(request);
      state.captureImageUploadingCount--;
      await _updateCaptureResultList();
      if (result) {
        logger.i('updateConsultationFilesInfoAsync success');
        return true;
      } else {
        logger.i('updateConsultationFilesInfoAsync failed');
        return false;
      }
    } catch (e) {
      state.captureImageUploadingCount--;
      if (isSingle) {
        PromptBox.toast(i18nBook.realTimeConsultation.captureFailed.t);
      } else {
        PromptBox.toast(i18nBook.realTimeConsultation.recordFailed.t);
      }
      return false;
    }
  }
}
