import 'dart:math';

import 'package:fis_common/index.dart';
import 'package:flyinsono/architecture/states/states.dart';
import 'package:flyinsono/architecture/utils/prompt_box.dart';
import 'package:flyinsono/lab/manager/interfaces/analysis.dart';
import 'package:flyinsono/lab/manager/page_manager.dart';
import 'package:flyinsono/lab/mock_data/mock_rpc.dart';
import 'package:flyinsono/lab/pages/lab_image/urm_data_processor/urm_data_processor.dart';
import 'package:flyinsono/lab/pages/lab_image/widgets/image_roi_sync/controller.dart';
import 'package:flyinsono/lab/pages/lab_image/widgets/widgets.dart';
import 'package:flyinsono/lab/router/lab_route_names.dart';
import 'package:flyinsono/managers/interfaces/remedical.dart';
import 'package:get/get.dart';
import 'index.dart';
import 'package:fis_ui/utils/sizer/sizer.dart';
import 'package:fis_measure/view/player/controller.dart';
import 'package:fis_jsonrpc/rpc.dart';
import 'package:fis_common/logger/logger.dart';
// import 'package:flyinsono/lab/mixin/tab_hook_mixin.dart';
// import 'package:flyinsono/lab/mock_data/mock_rpc.dart';

import 'widgets/widgets.dart';

class LabBatchAnalysisController extends GetxController {
  LabBatchAnalysisController({required this.tabHashCode, this.initArguments});

  final int tabHashCode;

  final dynamic initArguments;

  final state = LabBatchAnalysisState();

  final analysisManager = Get.find<IURMFunctionManager>();

  static const String labBatchAnalysisId = "lab_batch_analysis";

  // 整个图像页分为六个主要部分

  /// 1: 左侧图像选择器
  late final ImageDataToAnalysisController imageDataToAnalysisController;

  /// 2: 图像播放器
  late final ImageDataPlayerController imageDataPlayerController;

  /// 3: 播放进度控制器
  late final ProgressPanelController progressController;

  /// 4: 右侧操作面板
  late final UrmOperatePanelController urmOperatePanelController;

  /// 6. ROI 绘制层
  late final ImageRoiOverlayController imageRoiOverlayController;

  late VidPlayerController playerController;

  ///ROI同步（复制操作）控制器
  late final ImageRoiSyncController imageRoiSyncController;

  // 记录图像 id 与 已完成的 roi 结果映射
  final Map<String, RoiPosRelativeToImage> roiResultMap = {};

  //记录图像 id 与 已完成的 roi 结果,用于接口上传使用
  final Map<String, RoiResult> roiResults = {};

  //记录图像 id 与 已完成的 roi 结果,用于接口上传使用
  final Map<String, dynamic> frameInfos = {};

  // 当前的 URM 数据处理器
  URMDataProcessor currentURMProcessor = URMDataProcessor();

  // 选中了 URM 数据
  bool isURMData = false;

  String projectCode = "";

  // 遍历所有图像，如果已有 roi 数据，则加载
  void loadRoiResult(VidDataInfo image) {
    RoiPosRelativeToImage? roiPosRelativeToImage = roiResultMap[image.id];

    if (roiPosRelativeToImage == null &&
        imageRoiSyncController.isOpenSync &&
        image.imageType == ImageType.URM) {
      roiPosRelativeToImage = roiResultMap[imageRoiSyncController.imageId];
      if (roiPosRelativeToImage != null) {
        roiResultMap[image.id] = roiPosRelativeToImage;
        Future.delayed(Duration(milliseconds: 500), () {
          onRoiSelected();
        });
      }
    }
    imageRoiOverlayController.drawRoi(roiPosRelativeToImage);
    urmOperatePanelController.updateSelectedImageStatus(
      isURMData: image.imageType == ImageType.URM,
      selectedRoi: roiPosRelativeToImage != null,
    );
  }

  Future<void> onRoiSelected() async {
    String? imageId = imageDataToAnalysisController.selectedImageId;
    if (imageId == null) {
      return;
    }
    await currentURMProcessor.loadURMParams(newImageCode: imageId);
    currentURMProcessor.setCalculator();
    RoiResult? roi = imageRoiOverlayController.getRoiResult();
    if (roi != null) {
      if (_checkisValid(roi)) {
        roiResults[imageId] = roi;
      } else {
        PromptBox.toast('ROI区域不正确！');
      }
    }
    RoiPosRelativeToImage? roiResult =
        imageRoiOverlayController.getRoiRelativePos();
    if (roiResult == null) {
      return;
    }
    roiResultMap[imageId] = roiResult;
    imageDataToAnalysisController
        .updateRoiSelectedImageIds(roiResultMap.keys.toList());
    urmOperatePanelController.updateImageStatusCount(
      roiSelectedCount: roiResultMap.length,
    );
    urmOperatePanelController.updateSelectedImageStatus(
      isURMData: true,
      selectedRoi: true,
    );
  }

  // 图像选中事件【时序-1】
  void onImageSelected(VidDataInfo info) {
    _disableRoi();
    loadRoiResult(info);
    state.isImageDownloading = true;
    imageDataPlayerController.changeVid(
      info.vidUrl,
      info.coverUrl,
    );
    isURMData = info.imageType == ImageType.URM;
    currentURMProcessor = URMDataProcessor(
        imageCode: imageDataToAnalysisController.selectedImageId);
    imageRoiOverlayController.setURMDataProcessor(currentURMProcessor);
    imageRoiSyncController.updateFrameInfo(
        imageDataToAnalysisController.selectedImageId ?? '',
        frameInfos[info.id]);
  }

  // 图像数据加载完成事件【时序-2】
  void onDataHostLoaded(VidPlayerController playerController) {
    state.isImageDownloading = false;
    this.playerController = playerController;
    if (playerController.totalFramesCount == 1) {
      progressController.setProgressPanelEnable(false);
    } else {
      progressController.setProgressPanelEnable(true);
    }
  }

  void onFirstFrameLoaded(e) {
    print("首帧加载完成事件");
    imageDataPlayerController.changePlayStatus(false);
//
  }

  /// 图像数据缓冲进度事件
  void onBufferProgressChanged(double progress) {
    progressController.bufferProgress = progress;
  }

  // 图像帧尺寸变化事件【时序-3】(相同尺寸图像切换不一定会触发)
  void onFrameSizeChanged(int width, int height) {
    imageRoiOverlayController.setOverlaySize(width, height);
  }

  // 图像播放进度变化事件【时序-4】
  void onProgressChanged(VidProgressInfo progressInfo) {
    progressController.updateProgress(
      currentFrameIndex: progressInfo.currentFrame,
      totalFrames: progressInfo.totalFrames,
      totalDuration: progressInfo.totalDuration,
    );
    currentURMProcessor.loadVisualParams(playerController.currentFrame);
    if (isURMData) {
      _enableRoi();
    }
  }

  // 图像播放状态变化事件
  void onPlayStatusChanged(bool isPlaying) {
    progressController.updateStatus(isPlaying);
  }

  // 图像播放按钮点击事件
  void onPlayButtonClicked(bool isPlaying) {
    print("onPlayButtonClicked: $isPlaying");
    imageDataPlayerController.changePlayStatus(isPlaying);
  }

  /// 手动微调进度
  bool onFrameChangeEvent(int frame) {
    return imageDataPlayerController.onFrameChangeEvent(frame);
  }

  // 工具栏方法处理
  void methodCallHandler(UrmMethodCall methodCall) {
    switch (methodCall.type) {
      case UrmMethodType.URM_BATCH_ANALYSIS:
        print("URM_ANALYSIS");
        handleBatchURMAnalysis();
        break;
      default:
        break;
    }
  }

  void handleBatchURMAnalysis() async {
    List<AnalysisItem> analysisList = [];
    List<ImageModel> originImageDataList =
        imageDataToAnalysisController.getFilteredImageList();
    Store.app.busy = true;
    try {
      for (ImageModel image in originImageDataList) {
        String remedicalCode = image.id;
        RemedicalInfoDTO imageInfo = await Get.find<IRemedicalManager>()
            .findRemedicalByCode(remedicalCode);
        Map<String, String> urmParameters = imageInfo.urmParameters ?? {};
        int framesGot = 0;
        if (urmParameters.containsKey("FramesGot")) {
          framesGot = int.parse(urmParameters["FramesGot"]!);
        }
        if (imageDataToAnalysisController.roiSelectedImageIds
            .contains(remedicalCode)) {
          RoiResult? roi = roiResults[remedicalCode];
          List<int> frameInfo = frameInfos[remedicalCode] ?? [1, framesGot];
          if (roi == null) {
            continue;
          }
          analysisList.add(
            AnalysisItem(
              x: roi.startX.toDouble(),
              y: roi.startY.toDouble(),
              width: roi.width.toDouble(),
              height: roi.height.toDouble(),
              remedicalCode: remedicalCode,
              roiHPercent: roi.roiHPct,
              roiWPercent: roi.roiWPct,
              roiXPercent: roi.roiXPct,
              roiYPercent: roi.roiYPct,
              customizedStartFrame: max(1, frameInfo.first),
              customizedEndFrame: frameInfo.last,
            ),
          );
          print("roi已框选,执行局部分析");
        } else {
          NormCoord normCoordInRegion =
              await imageRoiSyncController.calNormCoordInFullImageByRoiInfo(
                  selectedImageId: remedicalCode, imageInfo: imageInfo);
          if (urmParameters.isEmpty) {
            continue;
          }
          var beams = urmParameters["Beams"];
          var samples = urmParameters["Samples"];
          if (beams.isNullOrEmpty || samples.isNullOrEmpty) {
            continue;
          }
          analysisList.add(
            AnalysisItem(
              x: 1,
              y: 1,
              width: double.parse(beams!) - 1,
              height: double.parse(samples!) - 1,
              remedicalCode: remedicalCode,
              customizedStartFrame: 1,
              customizedEndFrame: framesGot,
              roiHPercent: normCoordInRegion.heightPct,
              roiWPercent: normCoordInRegion.widthPct,
              roiXPercent: normCoordInRegion.xPct,
              roiYPercent: normCoordInRegion.yPct,
            ),
          );
          print("roi未框选,执行全局分析");
        }
      }
      await analysisManager.batchAnalysis(analysisList: analysisList);
    } catch (e) {
      logger.e('handleBatchURMAnalysis ex:', e);
      Store.app.busy = false;
    }
    Store.app.busy = false;
    PageManager.ins.closeTab(tabHashCode);
    PageManager.ins.openNewTab(
      LabRouteNames.TaskList,
      "任务列表",
      multiple: false,
    );
  }

  /// 禁用 ROI
  void _disableRoi() {
    imageRoiOverlayController.deactive();
  }

  /// 启用 ROI
  void _enableRoi() {
    imageRoiOverlayController.active();
  }

  /// 窗口大小变化事件
  void _onWindowResize(_) {
    imageRoiOverlayController.onRenderSizeChanged();
    // imageMeasureOverlayController.onRenderSizeChanged();
  }

  // @override
  // void onActive(arguments) {
  //   print("onActive $arguments");
  //   if (arguments is LabImageActiveArguments) {
  //     if (arguments.images.isNotEmpty) {
  //       state.noImage = false;
  //     } else {
  //       state.noImage = true;
  //       return;
  //     }
  //     // TODO 此处切换前需要有一个弹窗询问，如果有未保存的数据，是否保存并切换到新病人/新图像
  //     imageDataSourcePanelController.updateImageList(
  //       arguments.patient,
  //       arguments.record,
  //       arguments.images,
  //       arguments.selectedImageIndex,
  //     );
  //   }
  // }

  // @override
  // void onSleep() {
  //   print("onSleep");
  // }

  void onFrameChanged(dynamic frameInfo) {
    String? imageId = imageDataToAnalysisController.selectedImageId;
    if (imageId == null) {
      return;
    }

    frameInfos[imageId] = frameInfo;
  }

  /// 在 widget 内存中分配后立即调用。
  @override
  void onInit() {
    super.onInit();
    Sizer.ins.addListener(_onWindowResize);
    imageRoiOverlayController = ImageRoiOverlayController(
      onRoiSelected: onRoiSelected,
      setRoiPercentOffset: (percentOffset, imageCode) {
        imageRoiSyncController.setRoiPercentOffset(
          percentOffset,
          imageCode,
        );
      },
    );
    progressController = ProgressPanelController(
      onPlayButtonClicked: onPlayButtonClicked,
      onFrameChangeEvent: onFrameChangeEvent,
    );
    urmOperatePanelController = UrmOperatePanelController(
      onMethodCall: methodCallHandler,
    );
    imageDataPlayerController = ImageDataPlayerController(
      onProgressChanged: onProgressChanged,
      onPlayStatusChanged: onPlayStatusChanged,
      onFrameSizeChanged: onFrameSizeChanged,
      onDataHostLoaded: onDataHostLoaded,
      onFirstFrameLoaded: onFirstFrameLoaded,
      onBufferProgressChanged: onBufferProgressChanged,
    );
    imageDataToAnalysisController = ImageDataToAnalysisController(
      onImageSelected: onImageSelected,
    );
    imageRoiSyncController = ImageRoiSyncController(
      this,
      onFrameChanged: onFrameChanged,
    );
    print("LabBatchAnalysisController onInit initArguments: $initArguments");
    if (initArguments is LabBatchAnalysisInitArguments) {
      projectCode = initArguments.projectCode;
      if (initArguments.images.isNotEmpty) {
        // TODO
        // state.noImage = false;
      } else {
        // TODO
        // state.noImage = true;
        return;
      }
      // TODO 此处切换前需要有一个弹窗询问，如果有未保存的数据，是否保存并切换到新病人/新图像
      imageDataToAnalysisController.updateImageList(
        initArguments.patient,
        initArguments.record,
        initArguments.images,
      );
      int unSupportUrmCount = 0;
      for (ImageModel image in initArguments.images) {
        if (image.vidDataInfo.imageType != ImageType.URM) {
          unSupportUrmCount++;
        }
      }
      urmOperatePanelController.updateImageStatusCount(
        totalCount: initArguments.images.length,
        roiSelectedCount: 0,
        unSupportUrmCount: unSupportUrmCount,
      );
    }
  }

  /// 在 onInit() 之后调用 1 帧。这是进入的理想场所
  @override
  void onReady() {
    super.onReady();
  }

  /// 在 [onDelete] 方法之前调用。
  @override
  void onClose() {
    super.onClose();
    Sizer.ins.removeListener(_onWindowResize);
  }

  /// dispose 释放内存
  @override
  void dispose() {
    super.dispose();
    Sizer.ins.removeListener(_onWindowResize);
    imageDataPlayerController.dispose();
    progressController.dispose();
    urmOperatePanelController.dispose();
    imageDataToAnalysisController.dispose();
  }

  bool _checkisValid(RoiResult roiResult) {
    bool result = true;
    int rawBeams = currentURMProcessor.rawBeams;
    int rawSamples = currentURMProcessor.rawSamples;
    if (roiResult.startX > rawBeams) {
      result = false;
    }
    if (roiResult.startY > rawSamples) {
      result = false;
    }
    if (roiResult.startX + roiResult.width > rawBeams) {
      result = false;
    }
    if (roiResult.startY + roiResult.height > rawSamples) {
      result = false;
    }
    print(
        "roiPosRelativeToImage:${roiResult.startX} ${roiResult.startY} ${roiResult.width} ${roiResult.height}");

    return result;
  }
}

class LabBatchAnalysisInitArguments {
  final PatientModel patient;
  final RecordModel record;
  final List<ImageModel> images;
  final String projectCode;

  LabBatchAnalysisInitArguments({
    required this.patient,
    required this.record,
    required this.images,
    required this.projectCode,
  });
}
