import 'dart:math';
import 'dart:ui';
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/pages/lab_image/urm_data_processor/index.dart';
import 'package:flyinsono/rpc.dart';
import 'package:get/get.dart';
import 'package:vid/us/vid_us_image.dart';
import 'package:fis_measure/interfaces/process/urm/urm_data_processor.dart';
import 'package:flyinsono/managers/interfaces/remedical.dart';
import 'package:fis_jsonrpc/rpc.dart';
import 'package:fis_common/logger/logger.dart';

class URMDataProcessor extends IURMDataProcessor {
  // URM 分析相关参数
  GridArea roiArea = GridArea.empty(); // 内部存了 beam, sample信息
  int customizedStartFrame = 1; // 自定义起始帧
  int customizedEndFrame = 0; // 自定义结束帧
  // URM 参数（来自超声机传参）
  int framesGot = 0; // 需要 load
  int rawBeams = 0; // 需要 load
  int rawSamples = 0; // 需要 load
  String probeType = ""; // 探头型号 需要 load
  String rawTissueColorBar = ""; // 需要load
  String rawTimeMotionColorBar = ""; // 需要load
  double startTime = 0.0; // 需要load
  double endTime = 0.0; // 需要load
  bool isParamLoaded = false; // 基础参数是否已初始化完成
  URMVisualInfo visualInfo = URMVisualInfo(); // URM 视图参数
  // 可调后处理参数（前端面板中调节）
  UrmImageType urmImageType = UrmImageType.Den;
  UrmBlendType urmBlend = UrmBlendType.Close; // 混合: 默认关
  bool isSyncDisplay = true; // 同步显示
  int imgProcessVer = 1;
  // ZOOM 开关
  bool zoomOn = false;
  String? application;
  String? applicationCategory;
  double probeWidth = 0.0384; // Mock 参数，来自 ZHAO HAI MING 病例
  double urmMaxVal = 0.0; // urm最大值
  double urmMinVal = 0.0; // urm最小值
  int startingFrame = 0; // 起始帧
  int totalFrame = 0; // 总帧数
  int viewPortOffset = 0; // 视口偏移（由于超声机截图偏移造成 X 轴偏移）

  /// 是否是视频模式
  bool get isVideoMode => urmImageType == UrmImageType.Video;

  /// 用于URM后处理的可调节参数
  PostProcessImageParams postProcessImageParams = PostProcessImageParams();

  /// 用于URM后处理的位置参数
  ProcessPosParams processParams = ProcessPosParams();

  /// 可测量区域在完整视图中的归一化矩形
  Rect _measureAreaInFullVisual = Rect.zero;

  /// URM视图在完整视图中的归一化矩形
  Rect _urmScreenInFullVisual = Rect.zero;

  /// ROI 区域在可视 Visual 中的百分比坐标路径
  Path roiPathInVisual = Path();

  /// 用于zoom小窗预览的位置参数
  ProcessPosParams previewParams = ProcessPosParams();
  // 遮罩轨迹点【状态点集】
  List<Point<double>> urmTraceDPoints = [];

  ///接口用的轨迹点【接口用点集】
  List<UrmPoint> urmPoints = [];

  // 图像 Code
  String imageCode = '';
  // zoom 相关参数
  double zoomFactor = 1.0; // 缩放倍率
  Offset zoomOffset = Offset(0.5, 0.5); // 缩放偏移

  late IURMCalculator calculator; // 坐标计算器

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

  URMDataProcessor({
    String? imageCode,
  }) {
    this.imageCode = imageCode ?? '';
  }

  void setUrmTraceDPoints(List<Point<double>> points) {
    urmTraceDPoints.clear();
    urmTraceDPoints.addAll(points);
    urmPoints = urmTraceDPointsConvert(urmTraceDPoints);
  }

  // 根据绘制的 ROI 区域归一化数值计算 ROI 参数
  void calROIParam(NormCoord coord) {
    GridArea result = calculator.calROIParam(coord);
    roiArea = result;
  }

  /// 设置视图信息 =1
  void loadVisualParams(VidUsImage? vidUsImage) {
    if (vidUsImage == null) {
      return;
    }
    visualInfo.loadVisualParams(vidUsImage);
    print('修正视图偏移：$viewPortOffset');
    if (probeType == "Linear_X10-23L") {
      visualInfo.fixBeamsBoundaryByPixelOffset(viewPortOffset); // 修正由于传图错误导致的偏移
    }
  }

  /// 设置 URM 参数 = 2
  Future<void> loadURMParams(
      {String? newImageCode, RemedicalInfoDTO? newImageInfo}) async {
    if (newImageCode != null) {
      imageCode = newImageCode;
    }
    RemedicalInfoDTO imageInfo;
    if (newImageInfo == null) {
      imageInfo =
          await Get.find<IRemedicalManager>().findRemedicalByCode(imageCode);
    } else {
      imageInfo = newImageInfo;
    }
    application = imageInfo.application;
    applicationCategory = imageInfo.applicationCategory;
    String urmPosition = imageInfo.urmPosition ?? "";
    try {
      if (urmPosition.isNotEmpty) {
        List<String> urmPositions = urmPosition.split(",");
        if (urmPositions.length == 7) {
          print('存在 ROI 信息以及帧信息');
          String paramStartXStr = urmPositions[0];
          int startX = int.parse(paramStartXStr);
          String paramStartYStr = urmPositions[1];
          int startY = int.parse(paramStartYStr);
          String paramWidthStr = urmPositions[2];
          int width = int.parse(paramWidthStr);
          String paramHeightStr = urmPositions[3];
          int height = int.parse(paramHeightStr);
          roiArea = GridArea.fromXYWH(
            x: startX,
            y: startY,
            w: width,
            h: height,
          );
          String startingFrameStr = urmPositions[4];
          startingFrame = int.parse(startingFrameStr);
          String totalFrameStr = urmPositions[6];
          totalFrame = int.parse(totalFrameStr);
        }
      }
    } catch (err) {
      print('获取URM urmPosition参数失败：' + err.toString());
      logger.e('urmPosition ex:', err);
    }

    int beams = 0;
    int samples = 0;
    String tissueColorBar = "";
    String timeMotionColorBar = "";

    Map<String, String> urmParameters = imageInfo.urmParameters ?? {};
    final String beamsKey = "Beams";
    final String samplesKey = "Samples";

    final String tissueColorBarKey = "TissueColorBar";
    final String timeMotionColorBarKey = "TimeMotionColorBar";
    final String probeWidthKey = "ProbeWidth";
    final String startTimeKey = "StartTime";
    final String endTimeKey = "EndTime";

    final String typeInfoKey = "TypeInfo";
    final String viewPortOffsetKey = "ViewPortOffset";

    try {
      try {
        if (urmParameters.containsKey("FramesGot")) {
          framesGot = int.parse(urmParameters["FramesGot"]!);
          customizedEndFrame = framesGot;
        }
      } catch (e) {
        print('获取framesGot参数失败');
      }
      if (urmParameters.containsKey(beamsKey)) {
        beams = int.parse(urmParameters[beamsKey]!);
      } else {
        print('获取URM参数失败');
      }
      if (urmParameters.containsKey(samplesKey)) {
        samples = int.parse(urmParameters[samplesKey]!);
      } else {
        print('获取URM参数失败');
      }
      if (urmParameters.containsKey(tissueColorBarKey)) {
        tissueColorBar = urmParameters[tissueColorBarKey]!.toString();
      } else {
        print('获取URM参数失败');
      }
      if (urmParameters.containsKey(timeMotionColorBarKey)) {
        timeMotionColorBar = urmParameters[timeMotionColorBarKey]!.toString();
      } else {
        print('获取URM参数失败');
      }
      if (urmParameters.containsKey(probeWidthKey)) {
        probeWidth = double.parse(urmParameters[probeWidthKey]!);
      } else {
        print('获取URM参数失败');
      }

      if (urmParameters.containsKey(startTimeKey)) {
        startTime = double.parse(urmParameters[startTimeKey]!);
      } else {
        print('获取URM参数失败');
      }

      if (urmParameters.containsKey(endTimeKey)) {
        endTime = double.parse(urmParameters[endTimeKey]!);
      } else {
        print('获取URM参数失败');
      }
      if (urmParameters.containsKey(typeInfoKey)) {
        String typeInfo = urmParameters[typeInfoKey]!;
        probeType = typeInfo;
        postProcessImageParams.updateDefaultParamByProbeType(probeType);
      } else {
        print('获取URM参数失败');
      }
      if (urmParameters.containsKey(viewPortOffsetKey)) {
        viewPortOffset = int.parse(urmParameters[viewPortOffsetKey]!);
      } else {
        print('获取URM参数失败');
      }
      rawBeams = beams;
      rawSamples = samples;
      rawTissueColorBar = tissueColorBar;
      rawTimeMotionColorBar = timeMotionColorBar;
    } catch (err) {
      print('获取URM参数失败：' + err.toString());
      logger.e('loadURMParams ex:', err);
      return;
    }
    isParamLoaded = true;
  }

  /// 设置计算函数 (需要等 visualInfo 加载完成) =3
  void setCalculator() {
    if (isParamLoaded == false) {
      print('URM 参数未加载完成（需要先执行 loadURMParams）');
      return;
    }
    if (visualInfo.isVisualLoaded == false) {
      print('VID 视图参数未加载完成（需要先执行 loadVisualParams）');
      return;
    }

    calculator = visualInfo.isLinear
        ? LinearCalculator(
            visualInfo: visualInfo,
            rawBeams: rawBeams,
            rawSamples: rawSamples,
            probeWidth: probeWidth,
          )
        : CurvedCalculator(
            visualInfo: visualInfo,
            rawBeams: rawBeams,
            rawSamples: rawSamples,
            probeWidth: probeWidth,
          );
  }

  /// 获取ROI结果
  RoiResult getRoiResult() {
    NormCoord normCoordFullImage = calculator.calNormCoordInFullImage(roiArea);
    return RoiResult(
      startX: roiArea.beamStart,
      startY: roiArea.sampleStart,
      width: roiArea.width,
      height: roiArea.height,
      roiXPct: normCoordFullImage.xPct,
      roiYPct: normCoordFullImage.yPct,
      roiWPct: normCoordFullImage.widthPct,
      roiHPct: normCoordFullImage.heightPct,
    );
  }

  /// 获取完整图像内有效区域的归一化坐标 for Zoom Preview
  Rect getVisualRect() {
    if (visualInfo.isLeftRight) {
      return Rect.fromLTRB(visualInfo.beamsLeftBoundary / 2 + 0.5, 0,
          visualInfo.beamsRightBoundary / 2 + 0.5, 1);
    }
    return Rect.fromLTRB(
        visualInfo.beamsLeftBoundary, 0, visualInfo.beamsRightBoundary, 1);
  }

  /// 处理缩放中心变更事件
  void handleZoomCenterChange(Offset center) {
    zoomOffset = center;
    if (urmTraceDPoints.isNotEmpty) {
      urmPoints = urmTraceDPointsConvert(urmTraceDPoints);
    }
    print('zoomOffset 变更: $zoomOffset');
  }

  // 处理参数变更
  void handleParamChange(URMParamAdjust param) {
    print('参数变更: ${param.type} ${param.value}');
    switch (param.type) {
      case URMParamType.SyncDisplay:
        if (param.value is bool) {
          isSyncDisplay = param.value;
          if (urmTraceDPoints.isNotEmpty) {
            urmPoints = urmTraceDPointsConvert(urmTraceDPoints);
          }
        }
        break;
      case URMParamType.URMBlend:
        if (param.value is UrmBlendType) {
          urmBlend = param.value;
        }
        break;
      case URMParamType.UrmImageType:
        if (param.value is UrmImageType) {
          urmImageType = param.value;
        }
        break;
      case URMParamType.ZOOM:
        if (param.value is double) {
          zoomFactor = param.value;
          print('zoomFactor 变更: $zoomFactor');
          if (urmTraceDPoints.isNotEmpty) {
            urmPoints = urmTraceDPointsConvert(urmTraceDPoints);
          }
        }
        break;
      case URMParamType.DownsampleIndex:
      case URMParamType.IntPowerDen:
      case URMParamType.IntPowerDir:
      case URMParamType.SigmaGauss:
      case URMParamType.VessScale:
      case URMParamType.VelMaxScaler:
      case URMParamType.VelMinScaler:
      case URMParamType.Iterations:
      case URMParamType.URMVideoParameter:
      case URMParamType.URMVideoType:
      case URMParamType.URMVideoIndex:
        postProcessImageParams.setParam(param);
    }
  }

  // 计算后处理相关图像参数
  void calPostProcessImageParams() {
    zoomOn = zoomFactor != 1.0;
    processParams = calculator.calPostProcessImageParams(
      zoomFactor,
      zoomOffset,
      roiArea,
      isSyncDisplay,
    );

    _measureAreaInFullVisual = calculator.calMeasureAreaInFullVisual(
        zoomFactor, zoomOffset, isSyncDisplay, roiArea);
    _urmScreenInFullVisual = calculator.calURMScreenInFullVisual(
        zoomFactor, zoomOffset, isSyncDisplay, roiArea);
    roiPathInVisual = calculator.calRoiPathInVisual(
        zoomFactor, zoomOffset, isSyncDisplay, roiArea);
    print(
        "变换后的坐标系为 _measureAreaInFullVisual $_measureAreaInFullVisual _urmScreenInFullVisual $_urmScreenInFullVisual");
  }

  // 计算预览图参数
  void calPreviewImageParams() {
    previewParams = calculator.calPreviewImageParams(
      roiArea,
      isSyncDisplay,
    );
  }

  Future<String> getURMImage() async {
    if (!isParamLoaded) {
      await loadURMParams();
    }

    calPostProcessImageParams(); // 最重要的坐标系计算全在里面
    if (urmImageType == UrmImageType.Video) {
      return _getVideoPostProcessImage();
    } else {
      return _getPostProcessImage();
    }
  }

  // 使用当前参数获取后处理结果图像
  Future<String> _getVideoPostProcessImage() async {
    final request = URMVideoProcessRequest(
      remedicalCode: imageCode,
      urmImageType: "1",
      urmBlend: urmBlend.index,
      downsampleIndex: postProcessImageParams.downsampleIndex,
      intPowerDen: postProcessImageParams.intPowerDen,
      intPowerDir: postProcessImageParams.intPowerDir,
      sigmaGauss: postProcessImageParams.sigmaGauss,
      vessScale: postProcessImageParams.vessScale,
      velMaxScaler: postProcessImageParams.velMaxScaler,
      velMinScaler: postProcessImageParams.velMinScaler,
      iterations: postProcessImageParams.iterations,
      imgProcessVer: imgProcessVer,
      zoomOn: zoomOn,
      zoomRoix: processParams.zoomRoiX,
      zoomRoiy: processParams.zoomRoiY,
      zoomRoiwidth: processParams.zoomRoiW,
      zoomRoiheight: processParams.zoomRoiH,
      roix: processParams.roiX,
      roiy: processParams.roiY,
      roiwidth: processParams.roiW,
      roiheight: processParams.roiH,
      upDown: false,
      leftRight: false,
      screenWidth: processParams.screenW,
      screenHeight: processParams.screenH,
      urmTraceDPoints: urmPoints,
      videoFrame: (postProcessImageParams.urmVideoIndex).round(),
      uRMVideoType: postProcessImageParams.urmVideoType,
      uRMVideoParameter: postProcessImageParams.urmVideoParameter,
      uRMVideoScaler: 3,
    );
    String result = await analysisManager.runVideoPostProcess(
      request: request,
    );
    print("视频后处理AAAA  ${result.length}");
    return result;
  }

  List<UrmPoint> urmTraceDPointsConvert(List<Point<double>> points) {
    List<UrmPoint> result = [];
    // Rect rOIRangePercentArea = calculator.getROIRangePercent(roiArea);
    _urmScreenInFullVisual = calculator.calURMScreenInFullVisual(
        zoomFactor, zoomOffset, isSyncDisplay, roiArea);
    result = calculator.localToView(points, urmScreenInFullVisual);
    print(urmTraceDPoints.length);
    return result;
  }

  ///生成视频
  Future<String> saveAnalysisVideoByTask(
      String? base64, double? imageWidth, double? imageHeight) async {
    Rect visualRect = getVisualRect();
    var x = visualRect.left;
    var y = visualRect.top;
    var width = visualRect.width;
    var height = visualRect.height;
    double? leftImgTopLeftCornerXPercent;
    double? leftImgTopLeftCornerYPercent;
    double? rightImgTopLeftCornerXPercent;
    double? rightImgTopLeftCornerYPercent;
    double? colorBarXPercent;
    double? colorBarYPercent;
    if (isSyncDisplay) {
      x = visualRect.left;
      y = visualRect.top;
      width = visualRect.width;
      height = visualRect.height;
      leftImgTopLeftCornerXPercent = visualInfo.beamsLeftBoundary;
      rightImgTopLeftCornerXPercent = visualInfo.beamsLeftBoundary / 2 + 0.5;
      if (leftImgTopLeftCornerXPercent < (65 / imageWidth!)) {
        leftImgTopLeftCornerXPercent = 65 / imageWidth;
      }
      colorBarXPercent =
          visualInfo.beamsRightBoundary / 2 + 0.5 + 5 / imageWidth;
      //colorBarXPercent+10/ imageWidth > 1 是判断右上顶点是否超出右侧边界
      if (colorBarXPercent > 1 || colorBarXPercent + 10 / imageWidth > 1) {
        colorBarXPercent = 1 - 10 / imageWidth;
      }
      colorBarYPercent = (128 + 10) / imageHeight!;
      if (visualInfo.isLeftRight) {
        leftImgTopLeftCornerXPercent = leftImgTopLeftCornerXPercent / 2;
      }
    }

    SaveAnalysisVideoRequest request = SaveAnalysisVideoRequest(
      remedicalCode: imageCode,
      urmImageType: "1",
      urmBlend: urmBlend.index,
      downsampleIndex: postProcessImageParams.downsampleIndex,
      intPowerDen: postProcessImageParams.intPowerDen,
      intPowerDir: postProcessImageParams.intPowerDir,
      sigmaGauss: postProcessImageParams.sigmaGauss,
      vessScale: postProcessImageParams.vessScale,
      velMaxScaler: postProcessImageParams.velMaxScaler,
      velMinScaler: postProcessImageParams.velMinScaler,
      iterations: postProcessImageParams.iterations,
      imgProcessVer: imgProcessVer,
      zoomOn: zoomOn,
      zoomRoix: processParams.zoomRoiX,
      zoomRoiy: processParams.zoomRoiY,
      zoomRoiwidth: processParams.zoomRoiW,
      zoomRoiheight: processParams.zoomRoiH,
      roix: processParams.roiX,
      roiy: processParams.roiY,
      roiwidth: processParams.roiW,
      roiheight: processParams.roiH,
      upDown: false,
      leftRight: false,
      screenWidth: processParams.screenW,
      screenHeight: processParams.screenH,
      urmTraceDPoints: urmPoints,
      videoFrame: (postProcessImageParams.urmVideoIndex).round(),
      uRMVideoType: postProcessImageParams.urmVideoType,
      uRMVideoParameter: postProcessImageParams.urmVideoParameter,
      uRMVideoScaler: 3,
      backgroundImage: base64,
      roiXPercent: x,
      roiYPercent: y,
      roiWPercent: width,
      roiHPercent: height,
      leftImgTopLeftCornerXPercent: leftImgTopLeftCornerXPercent ?? 0,
      leftImgTopLeftCornerYPercent: leftImgTopLeftCornerYPercent ?? 0,
      rightImgTopLeftCornerXPercent: rightImgTopLeftCornerXPercent ?? 0,
      rightImgTopLeftCornerYPercent: rightImgTopLeftCornerYPercent ?? 0,
      colorBarXPercent: colorBarXPercent ?? 0,
      colorBarYPercent: colorBarYPercent ?? 0,
    );

    return await analysisManager.saveAnalysisVideoByTask(request);
  }

  // 使用当前参数获取后处理结果图像
  Future<String> _getPostProcessImage() async {
    final request = URMProcessRequest(
      remedicalCode: imageCode,
      urmImageType: urmImageType.index.toString(),
      urmBlend: urmBlend.index,
      downsampleIndex: postProcessImageParams.downsampleIndex,
      intPowerDen: postProcessImageParams.intPowerDen,
      intPowerDir: postProcessImageParams.intPowerDir,
      sigmaGauss: postProcessImageParams.sigmaGauss,
      vessScale: postProcessImageParams.vessScale,
      velMaxScaler: postProcessImageParams.velMaxScaler,
      velMinScaler: postProcessImageParams.velMinScaler,
      iterations: postProcessImageParams.iterations,
      imgProcessVer: imgProcessVer,
      zoomOn: zoomOn,
      zoomRoix: processParams.zoomRoiX,
      zoomRoiy: processParams.zoomRoiY,
      zoomRoiwidth: processParams.zoomRoiW,
      zoomRoiheight: processParams.zoomRoiH,
      roix: processParams.roiX,
      roiy: processParams.roiY,
      roiwidth: processParams.roiW,
      roiheight: processParams.roiH,
      upDown: false,
      leftRight: false,
      screenWidth: processParams.screenW,
      screenHeight: processParams.screenH,
      urmTraceDPoints: urmPoints,
    );
    URMProcessResult result = await analysisManager.runPostProcess(
      request: request,
    );
    urmMaxVal = result.urmMaxVal;
    urmMinVal = result.urmMinVal;

    print("后处理AAAA  ${result.base64String?.length}");
    return result.base64String ?? '';
  }

  Future<String> getURMPreviewImage() async {
    if (!isParamLoaded) {
      await loadURMParams();
    }
    calPreviewImageParams();
    final request = URMProcessRequest(
      remedicalCode: imageCode,
      urmImageType: urmImageType.index.toString(),
      urmBlend: urmBlend.index,
      downsampleIndex: postProcessImageParams.downsampleIndex,
      intPowerDen: postProcessImageParams.intPowerDen,
      intPowerDir: postProcessImageParams.intPowerDir,
      sigmaGauss: postProcessImageParams.sigmaGauss,
      vessScale: postProcessImageParams.vessScale,
      velMaxScaler: postProcessImageParams.velMaxScaler,
      velMinScaler: postProcessImageParams.velMinScaler,
      iterations: postProcessImageParams.iterations,
      imgProcessVer: imgProcessVer,
      zoomOn: false,
      zoomRoix: 0,
      zoomRoiy: 0,
      zoomRoiwidth: 1,
      zoomRoiheight: 1,
      roix: previewParams.roiX,
      roiy: previewParams.roiY,
      roiwidth: previewParams.roiW,
      roiheight: previewParams.roiH,
      upDown: false,
      leftRight: false,
      screenWidth: previewParams.screenW,
      screenHeight: previewParams.screenH,
      urmTraceDPoints: urmPoints,
    );
    URMProcessResult result = await analysisManager.runPostProcess(
      request: request,
    );
    urmMaxVal = result.urmMaxVal;
    urmMinVal = result.urmMinVal;
    print("后处理 Preview ${result.base64String?.length}");
    return result.base64String ?? '';
  }

  // 根据 VidUsImage 信息直接获取 ROI 在完整图像中的归一化坐标
  NormCoord getNormCoordInFullImage(VidUsImage vidUsImage, GridArea roiArea) {
    loadVisualParams(vidUsImage);
    setCalculator();
    return calculator.calNormCoordInFullImage(roiArea);
  }

  // 预加载 URM 测量
  Future<void> preLoadMeasureFunction() async {
    bool success = await rpc.aIDiagnosis
        .loadURMMeasureProcessAsync(URMMeasureProcessRequest(
      token: Store.user.token,
      remedicalCode: imageCode,
      urmImageType: urmImageType.index.toString(),
      urmBlend: urmBlend.index,
      downsampleIndex: postProcessImageParams.downsampleIndex,
      intPowerDen: postProcessImageParams.intPowerDen,
      intPowerDir: postProcessImageParams.intPowerDir,
      sigmaGauss: postProcessImageParams.sigmaGauss,
      vessScale: postProcessImageParams.vessScale,
      velMaxScaler: postProcessImageParams.velMaxScaler,
      velMinScaler: postProcessImageParams.velMinScaler,
      iterations: postProcessImageParams.iterations,
      imgProcessVer: imgProcessVer,
      zoomOn: zoomOn,
      zoomRoix: processParams.zoomRoiX,
      zoomRoiy: processParams.zoomRoiY,
      zoomRoiwidth: processParams.zoomRoiW,
      zoomRoiheight: processParams.zoomRoiH,
      roix: processParams.roiX,
      roiy: processParams.roiY,
      roiwidth: processParams.roiW,
      roiheight: processParams.roiH,
      upDown: false,
      leftRight: false,
      screenWidth: processParams.screenW,
      screenHeight: processParams.screenH,
      urmTraceDPoints: urmPoints,
    ));
    print('预加载URM测量 $success');
  }

  // 预加载 URM 视频播放器
  Future<bool> preLoadURMVideoProcessAsync() async {
    try {
      PromptBox.loading("视频加载中...");
      bool success =
          await rpc.aIDiagnosis.loadURMVideoProcessAsync(URMVideoProcessRequest(
        uRMVideoScaler: 3,
        uRMVideoType: postProcessImageParams.urmVideoType,
        uRMVideoParameter: postProcessImageParams.urmVideoParameter,
        videoFrame: (postProcessImageParams.urmVideoIndex).round(),
        token: Store.user.token,
        remedicalCode: imageCode,
        urmImageType: urmImageType.index.toString(),
        urmBlend: urmBlend.index,
        downsampleIndex: postProcessImageParams.downsampleIndex,
        intPowerDen: postProcessImageParams.intPowerDen,
        intPowerDir: postProcessImageParams.intPowerDir,
        sigmaGauss: postProcessImageParams.sigmaGauss,
        vessScale: postProcessImageParams.vessScale,
        velMaxScaler: postProcessImageParams.velMaxScaler,
        velMinScaler: postProcessImageParams.velMinScaler,
        iterations: postProcessImageParams.iterations,
        imgProcessVer: imgProcessVer,
        zoomOn: zoomOn,
        zoomRoix: processParams.zoomRoiX,
        zoomRoiy: processParams.zoomRoiY,
        zoomRoiwidth: processParams.zoomRoiW,
        zoomRoiheight: processParams.zoomRoiH,
        roix: processParams.roiX,
        roiy: processParams.roiY,
        roiwidth: processParams.roiW,
        roiheight: processParams.roiH,
        upDown: false,
        leftRight: false,
        screenWidth: processParams.screenW,
        screenHeight: processParams.screenH,
        urmTraceDPoints: urmPoints,
      ));
      print('预加载URM视频播放器 $success');
      PromptBox.dismiss();
      return success;
    } catch (e) {
      PromptBox.dismiss();
      return false;
    }
  }

  @override
  URMMeasureParams getURMMeasureParams() {
    return URMMeasureParams(
      remedicalCode: imageCode,
      urmImageType: urmImageType.index.toString(),
      urmBlend: urmBlend.index,
      downsampleIndex: postProcessImageParams.downsampleIndex,
      intPowerDen: postProcessImageParams.intPowerDen,
      intPowerDir: postProcessImageParams.intPowerDir,
      sigmaGauss: postProcessImageParams.sigmaGauss,
      vessScale: postProcessImageParams.vessScale,
      velMaxScaler: postProcessImageParams.velMaxScaler,
      velMinScaler: postProcessImageParams.velMinScaler,
      iterations: postProcessImageParams.iterations,
      imgProcessVer: imgProcessVer,
      zoomOn: zoomOn,
      zoomRoix: processParams.zoomRoiX,
      zoomRoiy: processParams.zoomRoiY,
      zoomRoiwidth: processParams.zoomRoiW,
      zoomRoiheight: processParams.zoomRoiH,
      roix: processParams.roiX,
      roiy: processParams.roiY,
      roiwidth: processParams.roiW,
      roiheight: processParams.roiH,
      leftRight: false,
      upDown: false,
      screenWidth: processParams.screenW,
      screenHeight: processParams.screenH,
      urmTraceDPoints: urmPoints,
    );
  }

  @override
  Rect get measureAreaInFullVisual => _measureAreaInFullVisual;
  @override
  Rect get urmScreenInFullVisual => _urmScreenInFullVisual;
  @override
  double get fullVisualPhywidth => visualInfo.regionWidth;
  @override
  bool get showLeftRight => visualInfo.isLeftRight && isSyncDisplay;
  @override
  bool get isLeftRight => visualInfo.isLeftRight;
}

// Roi 框相对于有效区域的归一化坐标
class NormCoord {
  final double xPct;
  final double yPct;
  final double widthPct;
  final double heightPct;

  NormCoord({
    required this.xPct,
    required this.yPct,
    required this.widthPct,
    required this.heightPct,
  });

  @override
  String toString() {
    return 'NormCoordInRegion {x: $xPct, y: $yPct, width: $widthPct, height: $heightPct}';
  }

  // 修正内部参数，将小于0的值修正为0，大于1的值修正为1
  NormCoord getFixedNormCoord() {
    return NormCoord(
      xPct: xPct < 0
          ? 0
          : xPct > 1
              ? 1
              : xPct,
      yPct: yPct < 0
          ? 0
          : yPct > 1
              ? 1
              : yPct,
      widthPct: widthPct < 0
          ? 0
          : widthPct > 1
              ? 1
              : widthPct,
      heightPct: heightPct < 0
          ? 0
          : heightPct > 1
              ? 1
              : heightPct,
    );
  }
}

// Roi 框相对于图像的位置（用于前端绘制）
class RoiPosRelativeToImage {
  final double x;
  final double y;
  final double width;
  final double height;

  RoiPosRelativeToImage({
    required this.x,
    required this.y,
    required this.width,
    required this.height,
  });

  @override
  String toString() {
    return 'RoiPosRelativeToImage{x: $x, y: $y, width: $width, height: $height}';
  }
}

// Roi 信息，用于提交给接口分析
class RoiResult {
  final int startX;
  final int startY;
  final int width;
  final int height;
  final double roiXPct;
  final double roiYPct;
  final double roiWPct;
  final double roiHPct;

  RoiResult({
    required this.startX,
    required this.startY,
    required this.width,
    required this.height,
    required this.roiXPct,
    required this.roiYPct,
    required this.roiWPct,
    required this.roiHPct,
  }) : assert(
            startX > 0 && startY > 0, "startX, startY must be greater than 0");
}

class URMParamAdjust {
  URMParamType type;
  dynamic value;
  URMParamAdjust({
    required this.type,
    required this.value,
  });
}
