import 'dart:math';
import 'dart:ui';
import 'package:flyinsono/lab/pages/lab_image/urm_data_processor/index.dart';
import 'package:fis_jsonrpc/services/researchEdition.m.dart';

// 线阵计算
class LinearCalculator extends IURMCalculator {
  LinearCalculator({
    required URMVisualInfo visualInfo,
    required int rawBeams,
    required int rawSamples,
    required double probeWidth,
  }) : super(
          visualInfo: visualInfo,
          rawBeams: rawBeams,
          rawSamples: rawSamples,
          probeWidth: probeWidth,
        );

  // 根据绘制的 ROI 区域归一化数值计算 ROI 区域参数
  @override
  GridArea calROIParam(NormCoord coord) {
    final uiCoord = correctUICoord(coord); // 第一道转换 ✅ 已完成
    final beamStart = ((uiCoord.xPct) * (rawBeams - 1)).round();
    final beamEnd =
        ((uiCoord.xPct + uiCoord.widthPct) * (rawBeams - 1)).round();
    final sampleStart = (uiCoord.yPct * (rawSamples - 1)).round();
    final sampleEnd =
        ((uiCoord.yPct + uiCoord.heightPct) * (rawSamples - 1)).round();
    // for matlab analysis  Point Index +1
    return GridArea(
      beamStart: beamStart + 1,
      beamEnd: beamEnd + 1,
      sampleStart: sampleStart + 1,
      sampleEnd: sampleEnd + 1,
    );
  }

  /// 基于 ROI 信息计算 ROI 在完整图像中的归一化坐标
  @override
  NormCoord calNormCoordInFullImage(GridArea roiArea) {
    final roiXPct =
        (roiArea.beamStart - 1) / rawBeams * visualInfo.beamsRangePercent +
            visualInfo.beamsLeftBoundary;
    final roiYPct = (roiArea.sampleStart - 1) / rawSamples;
    final roiWPct = ((roiArea.beamEnd - roiArea.beamStart)) /
        rawBeams *
        visualInfo.beamsRangePercent;
    final roiHPct = ((roiArea.sampleEnd - roiArea.sampleStart)) / rawSamples;
    NormCoord dataCoord = correctDataCoord(NormCoord(
      xPct: roiXPct,
      yPct: roiYPct,
      widthPct: roiWPct,
      heightPct: roiHPct,
    )); // 第二道转换 完成 ✅
    if (visualInfo.isLeftRight) {
      return NormCoord(
        xPct: dataCoord.xPct / 2 + 0.5,
        yPct: dataCoord.yPct,
        widthPct: (dataCoord.widthPct) / 2,
        heightPct: dataCoord.heightPct,
      );
    } else {
      return dataCoord;
    }
  }

  /// 获取 ROI 区域在完整视图下的归一化坐标范围
  @override
  Rect getROIPercentRect(GridArea area) {
    double left = area.beamStart / rawBeams;
    left = correctDataCoordX(left);
    double top = area.sampleStart / rawSamples;
    double width = area.width / rawBeams;
    width = correctDataCoordWidth(width);
    double height = area.height / rawSamples;
    return Rect.fromLTWH(
      left,
      top,
      width,
      height,
    );
  }

  /// 获取 ROI 区域相对于完整视图的缩放比
  double getROIScaleRatio(GridArea area) {
    // 宽度缩放比
    double widthScale = area.width / rawBeams;
    widthScale = correctDataCoordWidth(widthScale);
    // 高度缩放比
    final double heightScale = area.height / rawSamples;
    return max(widthScale, heightScale);
  }

  /// 基于起点终点坐标信息计算 ROI 在有效区域中的归一化坐标
  @override
  NormCoord calNormCoordInRegionByRoiPos(RoiPosRelativeToImage roiPos) {
    final double x = roiPos.x;
    final double y = roiPos.y;
    final double width = roiPos.width;
    final double height = roiPos.height;
    return NormCoord(
      xPct: (x - visualInfo.beamsLeftBoundary) / visualInfo.beamsRangePercent,
      yPct: y,
      widthPct: width / visualInfo.beamsRangePercent,
      heightPct: height,
    );
  }

  /// 计算用于后处理的坐标信息
  @override
  ProcessPosParams calPostProcessImageParams(double zoomFactor,
      Offset zoomOffset, GridArea roiArea, bool syncDisplay) {
    double zoomRoiX = 0;
    double zoomRoiY = 0;
    double zoomRoiW = 1;
    double zoomRoiH = 1;
    int roiX = 0;
    int roiY = 0;
    int roiW = 0;
    int roiH = 0;
    int screenW = 0;
    int screenH = 0;
    GridArea localRoiArea = GridArea(
      beamEnd: roiArea.beamEnd - 1,
      beamStart: roiArea.beamStart - 1,
      sampleEnd: roiArea.sampleEnd - 1,
      sampleStart: roiArea.sampleStart - 1,
    );
    if (visualInfo.isLeftRight) {
      screenW = ((visualInfo.width / 2) * visualInfo.beamsRangePercent).round();
    } else {
      screenW = (visualInfo.width * visualInfo.beamsRangePercent).round();
    }
    screenH = visualInfo.height;
    if (syncDisplay) {
      double roiXPctDouble = (localRoiArea.beamStart / rawBeams);
      roiX = (correctDataCoordX(roiXPctDouble) * screenW).round();
      roiY = (localRoiArea.sampleStart / rawSamples * screenH).round();
      double roiWPctDouble =
          ((localRoiArea.beamEnd - localRoiArea.beamStart) / rawBeams);
      roiW = (correctDataCoordWidth(roiWPctDouble) * screenW).round();
      roiH = ((localRoiArea.sampleEnd - localRoiArea.sampleStart) /
              rawSamples *
              screenH)
          .round();
      if (zoomFactor > 1.0) {
        Rect newRoiRect = Rect.fromLTWH(
            (roiX.toDouble() - (zoomOffset.dx * screenW)) * zoomFactor +
                screenW / 2,
            (roiY.toDouble() - (zoomOffset.dy * screenH)) * zoomFactor +
                screenH / 2,
            roiW.toDouble() * zoomFactor,
            roiH.toDouble() * zoomFactor);
        Rect screenRect =
            Rect.fromLTWH(0, 0, screenW.toDouble(), screenH.toDouble());
        // 取交集
        Rect intersectRect = newRoiRect.intersect(screenRect);
        roiX = intersectRect.left.round();
        roiY = intersectRect.top.round();
        roiW = intersectRect.width.round();
        roiH = intersectRect.height.round();
        Rect normalizedRect = getNormalizedRect(intersectRect, newRoiRect);
        zoomRoiX = normalizedRect.left;
        zoomRoiY = normalizedRect.top;
        zoomRoiW = normalizedRect.width;
        zoomRoiH = normalizedRect.height;
      }
    } else {
      final int virtualW = 800;
      final int virtualH = 600;
      double roiWPctDouble =
          ((localRoiArea.beamEnd - localRoiArea.beamStart) / rawBeams);
      roiW = (correctDataCoordWidth(roiWPctDouble) * screenW).round();
      roiH = ((localRoiArea.sampleEnd - localRoiArea.sampleStart) /
              rawSamples *
              screenH)
          .round();
      // 计算缩放因子，确保图像比例不变
      final double scale = (virtualW / roiW).clamp(0.0, virtualH / roiH);
      screenW = (roiW * scale).round();
      screenH = (roiH * scale).round();
      roiX = 0;
      roiY = 0;
      roiW = screenW;
      roiH = screenH;
      if (zoomFactor > 1.0) {
        Rect newRoiRect = Rect.fromLTWH(
            (roiX.toDouble() - (zoomOffset.dx * screenW)) * zoomFactor +
                screenW / 2,
            (roiY.toDouble() - (zoomOffset.dy * screenH)) * zoomFactor +
                screenH / 2,
            roiW.toDouble() * zoomFactor,
            roiH.toDouble() * zoomFactor);
        Rect screenRect =
            Rect.fromLTWH(0, 0, screenW.toDouble(), screenH.toDouble());
        // 取交集
        Rect intersectRect = newRoiRect.intersect(screenRect);
        roiX = intersectRect.left.round();
        roiY = intersectRect.top.round();
        roiW = intersectRect.width.round();
        roiH = intersectRect.height.round();
        Rect normalizedRect = getNormalizedRect(intersectRect, newRoiRect);
        zoomRoiX = normalizedRect.left;
        zoomRoiY = normalizedRect.top;
        zoomRoiW = normalizedRect.width;
        zoomRoiH = normalizedRect.height;
      }
    }

    return ProcessPosParams(
      zoomRoiX: zoomRoiX,
      zoomRoiY: zoomRoiY,
      zoomRoiW: zoomRoiW,
      zoomRoiH: zoomRoiH,
      roiX: roiX,
      roiY: roiY,
      roiW: roiW,
      roiH: roiH,
      screenW: screenW,
      screenH: screenH,
    );
  }

  /// 计算用于预览图像的坐标信息
  @override
  ProcessPosParams calPreviewImageParams(GridArea roiArea, bool syncDisplay) {
    int roiX = 0;
    int roiY = 0;
    int roiW = 0;
    int roiH = 0;
    int screenW = 0;
    int screenH = 0;
    GridArea localRoiArea = GridArea(
      beamEnd: roiArea.beamEnd - 1,
      beamStart: roiArea.beamStart - 1,
      sampleEnd: roiArea.sampleEnd - 1,
      sampleStart: roiArea.sampleStart - 1,
    );
    if (visualInfo.isLeftRight) {
      screenW = ((visualInfo.width / 2) * visualInfo.beamsRangePercent).round();
    } else {
      screenW = (visualInfo.width * visualInfo.beamsRangePercent).round();
    }
    screenH = visualInfo.height;
    if (syncDisplay) {
      double roiXPctDouble = (localRoiArea.beamStart / rawBeams);
      roiX = (correctDataCoordX(roiXPctDouble) * screenW).round();
      roiY = (localRoiArea.sampleStart / rawSamples * screenH).round();
      double roiWPctDouble =
          ((localRoiArea.beamEnd - localRoiArea.beamStart) / rawBeams);
      roiW = (correctDataCoordWidth(roiWPctDouble) * screenW).round();
      roiH = ((localRoiArea.sampleEnd - localRoiArea.sampleStart) /
              rawSamples *
              screenH)
          .round();
    } else {
      double roiWPctDouble =
          ((localRoiArea.beamEnd - localRoiArea.beamStart) / rawBeams);
      roiW = (correctDataCoordWidth(roiWPctDouble) * screenW).round();
      roiH = ((localRoiArea.sampleEnd - localRoiArea.sampleStart) /
              rawSamples *
              screenH)
          .round();
      screenW = roiW;
      screenH = roiH;
    }
    return ProcessPosParams(
      roiX: roiX,
      roiY: roiY,
      roiW: roiW,
      roiH: roiH,
      screenW: screenW,
      screenH: screenH,
    );
  }

  /// 计算当前可测量区域（测量图层）在完整视图(包含黑边)中的归一化矩形 ✅ 已完成
  Rect calMeasureAreaInFullVisual(
      double zoomFactor, Offset zoomOffset, bool isSyncDisplay, GridArea area) {
    if (isSyncDisplay) {
      // zoom 中心点在完整视图中的归一化坐标
      Offset zoomCenter = pointPctOutRect(visualRect, zoomOffset);
      return Rect.fromCenter(
          center: zoomCenter, width: 1 / zoomFactor, height: 1 / zoomFactor);
    } else {
      // 同步显示没开的情况下
      // 双幅下取半宽
      double leftRightHalfHalfWidth = visualInfo.isLeftRight
          ? (visualInfo.width / 2)
          : visualInfo.width.toDouble();
      // roi 区域的像素宽高
      double roiPixelWidth = (area.width / rawBeams);
      roiPixelWidth = correctDataCoordWidth(roiPixelWidth) *
          leftRightHalfHalfWidth *
          visualInfo.beamsRangePercent;
      double roiPixelHeight = area.height / rawSamples * visualInfo.height;
      // roi 区域相比于有效区域的比值
      Rect roiInFullVisual = getROIPercentRect(area);
      Offset zoomCenter = pointPctOutRect(roiInFullVisual, zoomOffset);
      Offset newZoomCenter = pointPctOutRect(visualRect, zoomCenter);
      // 计算出 ROI 区域的宽高比 R1
      double roiAspectRatio = roiPixelWidth / roiPixelHeight;
      // 计算出 可测量区域的宽高比 R2
      double measureAspectRatio = visualInfo.width / visualInfo.height;
      // R1 R2 做比较 得到 isWidthScale
      bool isWidthScale = roiAspectRatio > measureAspectRatio;

      double scaleWidth = 1;
      double scaleHeight = 1;
      if (isWidthScale) {
        // 如果基于宽度撑满的情况：计算roi区域在有效的区域的百分比*有效区域在完整视图的百分比
        scaleWidth = roiInFullVisual.width * visualInfo.beamsRangePercent;
        scaleHeight = scaleWidth / measureAspectRatio;
      } else {
        // 如果基于高度撑满的情况：计算roi区域在有效的区域的百分比==1*有效区域在完整视图的百分比
        scaleHeight = roiInFullVisual.height;
        scaleWidth = scaleHeight * measureAspectRatio;
      }
      return Rect.fromCenter(
        center: newZoomCenter,
        width: 1 / zoomFactor * scaleWidth,
        height: 1 / zoomFactor * scaleHeight,
      );
    }
  }

  /// 计算当前URM视图在完整视图中的归一化矩形
  Rect calURMScreenInFullVisual(
      double zoomFactor, Offset zoomOffset, bool isSyncDisplay, GridArea area) {
    Offset zoomCenter = pointPctOutRect(visualRect, zoomOffset);
    double width = (1 / zoomFactor) * visualInfo.beamsRangePercent;
    double height = 1 / zoomFactor;
    if (!isSyncDisplay) {
      Rect roiInFullVisual = getROIPercentRect(area);
      zoomCenter = pointPctOutRect(roiInFullVisual, zoomCenter);
      width = width * roiInFullVisual.width;
      height = height * roiInFullVisual.height;
    }
    var result =
        Rect.fromCenter(center: zoomCenter, width: width, height: height);
    return result;
  }

  // 本地完整图像内归一化坐标转视图内归一化坐标
  List<UrmPoint> localToView(
      List<Point<double>> points, Rect urmScreenInFullVisual) {
    List<UrmPoint> result = [];
    for (var p in points) {
      Offset percentOffset = Offset(p.x, p.y);
      percentOffset = pointPctInRect(urmScreenInFullVisual, percentOffset);
      result.add(UrmPoint(x: percentOffset.dx, y: percentOffset.dy));
    }
    return result;
  }

  // 基于 boundry 来修正 roi ，参考来自 超声机代码 GetMovementBoundary 方法
  // 第一道转换 (UI -> 数据)
  NormCoord correctUICoord(NormCoord uiCoord) {
    double widthPct = visualInfo.scanWidth / probeWidth / 100;
    double xOffsetPct = (1 - widthPct) / 2;
    return NormCoord(
      xPct: uiCoord.xPct * widthPct + xOffsetPct,
      yPct: uiCoord.yPct,
      widthPct: widthPct * uiCoord.widthPct,
      heightPct: uiCoord.heightPct,
    );
  }

  // 可以优化
  double correctUICoordX(double xPct) {
    double widthPct = visualInfo.scanWidth / probeWidth / 100;
    double xOffsetPct = (1 - widthPct) / 2;
    return xPct * widthPct + xOffsetPct;
  }

  // 可以优化
  double correctUICoordWidth(double widthPct) {
    double widthPct2 = visualInfo.scanWidth / probeWidth / 100;
    return widthPct2 * widthPct;
  }

  // 第二道转换 (数据 -> UI)
  NormCoord correctDataCoord(NormCoord dataCoord) {
    double widthPct = visualInfo.scanWidth / probeWidth / 100;
    double xOffsetPct = (1 - widthPct) / 2;
    return NormCoord(
      xPct: (dataCoord.xPct - xOffsetPct) / widthPct,
      yPct: dataCoord.yPct,
      widthPct: dataCoord.widthPct / widthPct,
      heightPct: dataCoord.heightPct,
    );
  }

  // 可以优化
  double correctDataCoordX(double xPct) {
    double widthPct = visualInfo.scanWidth / probeWidth / 100;
    double xOffsetPct = (1 - widthPct) / 2;
    return (xPct - xOffsetPct) / widthPct;
  }

  // 可以优化
  double correctDataCoordWidth(double widthPct) {
    double widthPct2 = visualInfo.scanWidth / probeWidth / 100;
    return widthPct / widthPct2;
  }

  /// 获取ROI在Urm视图中的归一化路径
  Path calRoiPathInVisual(
      double zoomFactor, Offset zoomOffset, bool isSyncDisplay, GridArea area) {
    final ProcessPosParams params =
        calPostProcessImageParams(zoomFactor, zoomOffset, area, isSyncDisplay);
    final Rect roiRect = Rect.fromLTWH(
      params.roiX / params.screenW,
      params.roiY / params.screenH,
      params.roiW / params.screenW,
      params.roiH / params.screenH,
    );
    final Path path = Path();
    path.addRect(roiRect);
    return path;
  }
}
