import 'dart:math';
import 'package:flutter/rendering.dart';
import 'package:flyinsono/lab/pages/lab_image/urm_data_processor/calculator/sector_shape.dart';
import 'package:fis_jsonrpc/services/researchEdition.m.dart';
import 'package:flyinsono/lab/pages/lab_image/urm_data_processor/index.dart';

// 弧阵计算
class CurvedCalculator extends IURMCalculator {
  CurvedCalculator({
    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 beamStart = ((coord.xPct) * (rawBeams - 1)).round();
    final beamEnd =
        (min(1, (coord.xPct + coord.widthPct)) * (rawBeams - 1)).round();
    final sampleStart = (coord.yPct * (rawSamples - 1)).round();
    final sampleEnd =
        (min(1, (coord.yPct + coord.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) {
    // 基于 ROI 信息计算 ROI 的外接矩形
    final getBoundingBox = getROIPercentRect(roiArea);
    print("getBoundingBox: $getBoundingBox");
    final roiXPct = getBoundingBox.left;
    final roiYPct = getBoundingBox.top;
    final roiWPct = getBoundingBox.width;
    final roiHPct = getBoundingBox.height;

    if (visualInfo.isLeftRight) {
      return NormCoord(
        xPct: roiXPct / 2 + 0.5,
        yPct: roiYPct,
        widthPct: (roiWPct) / 2,
        heightPct: roiHPct,
      );
    } else {
      return NormCoord(
        xPct: roiXPct,
        yPct: roiYPct,
        widthPct: roiWPct,
        heightPct: roiHPct,
      );
    }
  }

  /// 基于起点终点坐标信息计算 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;
    // 图像区域宽高
    final double rectHeight =
        visualInfo.physicalBottom - visualInfo.physicalTop;
    final double rectWidth = visualInfo.physicalRight - visualInfo.physicalLeft;
    final Offset zeroCenterOffset = visualInfo.zeroCenterOffset;
    // 起点和终点分别需要计算出其角度和深度，然后将其与图像的角度和深度作比较，得到归一化信息
    final Offset startPoint =
        (Offset(x, y) - zeroCenterOffset).scale(rectWidth, rectHeight);
    final Offset endPoint = (Offset(x + width, y + height) - zeroCenterOffset)
        .scale(rectWidth, rectHeight);
    // 计算起点和终点的角度和深度
    final double startDepth = startPoint.distance - visualInfo.zeroRadius;
    final double endDepth = endPoint.distance - visualInfo.zeroRadius;
    final double startAngleRadians = startPoint.direction; // 转为角度值
    final double endAngleRadians = endPoint.direction; // 转为角度值
    final double startAngle = 90 - startAngleRadians * 180 / pi;
    final double endAngle = 90 - endAngleRadians * 180 / pi;
    print("startAngle: $startAngle, endAngle: $endAngle");
    print("startDepth: $startDepth, endDepth: $endDepth");
    // 最小深度，最大深度，最小角度，最大角度
    final double minDepth = visualInfo.depthStart;
    final double maxDepth = visualInfo.depthEnd;
    final double minAngle = visualInfo.scanWidth / 2 * -1; // 40 / 2 * -1 = -20°
    final double maxAngle = visualInfo.scanWidth / 2; // 40 / 2 = 20°

    // 计算深度和角度的归一化值
    final double xPct = (startAngle - minAngle) / (maxAngle - minAngle);
    final double yPct = (startDepth - minDepth) / (maxDepth - minDepth);
    final double widthPct = (endAngle - startAngle) / (maxAngle - minAngle);
    final double heightPct = (endDepth - startDepth) / (maxDepth - minDepth);

    print(
        "xPct = $xPct, yPct = $yPct, widthPct = $widthPct, heightPct = $heightPct");
    return NormCoord(
      xPct: xPct,
      yPct: yPct,
      widthPct: widthPct,
      heightPct: heightPct,
    );
  }

  @override
  ProcessPosParams calPostProcessImageParams(double zoomFactor,
      Offset zoomOffset, GridArea roiArea, bool syncDisplay) {
    double zoomRoiX = 0;
    double zoomRoiY = 0;
    double zoomRoiW = 0;
    double zoomRoiH = 0;
    int roiX = 0;
    int roiY = 0;
    int roiW = 0;
    int roiH = 0;
    int screenW = 0;
    int screenH = 0;
    if (visualInfo.isLeftRight) {
      screenW = ((visualInfo.width / 2) * visualInfo.beamsRangePercent).round();
    } else {
      screenW = (visualInfo.width * visualInfo.beamsRangePercent).round();
    }
    screenH = visualInfo.height;
    // 基于 ROI 信息计算 ROI 的外接矩形
    final Rect boundingBox = getROIPercentRect(roiArea);
    roiX = (boundingBox.left * screenW).round();
    roiY = (boundingBox.top * screenH).round();
    roiW = (boundingBox.width * screenW).round();
    roiH = (boundingBox.height * screenH).round();

    if (syncDisplay) {
      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;
      // 计算缩放因子，确保图像比例不变
      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;
    if (visualInfo.isLeftRight) {
      screenW = ((visualInfo.width / 2) * visualInfo.beamsRangePercent).round();
    } else {
      screenW = (visualInfo.width * visualInfo.beamsRangePercent).round();
    }
    screenH = visualInfo.height;
    // 基于 ROI 信息计算 ROI 的外接矩形
    final Rect boundingBox = getROIPercentRect(roiArea);
    roiX = (boundingBox.left * screenW).round();
    roiY = (boundingBox.top * screenH).round();
    roiW = (boundingBox.width * screenW).round();
    roiH = (boundingBox.height * screenH).round();
    if (!syncDisplay) {
      roiX = 0;
      roiY = 0;
      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) *
          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;
  }

  /// 根据 GridArea 获取外接矩形
  @override
  Rect getROIPercentRect(GridArea roiArea) {
    // 最小深度，最大深度，最小角度，最大角度
    final double minDepth = visualInfo.depthStart;
    final double maxDepth = visualInfo.depthEnd;
    final double minAngle = visualInfo.scanWidth / 2 * -1; // 40 / 2 * -1 = -20°
    final double maxAngle = visualInfo.scanWidth / 2; // 40 / 2 = 20°
    // 角度起点和终点
    final double startAngle =
        (roiArea.beamStart - 1) / rawBeams * (maxAngle - minAngle) + minAngle;
    final double endAngle =
        (roiArea.beamEnd - 1) / rawBeams * (maxAngle - minAngle) + minAngle;

    // 深度起点和终点
    final double startDepth =
        (roiArea.sampleStart - 1) / rawSamples * (maxDepth - minDepth) +
            minDepth;
    final double endDepth =
        (roiArea.sampleEnd - 1) / rawSamples * (maxDepth - minDepth) + minDepth;
    // 小圆半径
    final innerRadius = startDepth + visualInfo.zeroRadius;
    // 大圆半径
    final outRadius = endDepth + visualInfo.zeroRadius;
    // 图像区域宽高
    final double rectWidth = visualInfo.physicalRight - visualInfo.physicalLeft;
    final double rectHeight =
        visualInfo.physicalBottom - visualInfo.physicalTop;
    // 中心点
    final Offset center =
        visualInfo.zeroCenterOffset.scale(rectWidth, rectHeight);
    // 角度转弧度
    final double startAngleRad = (90 - startAngle) * pi / 180;
    final double endAngleRad = (90 - endAngle) * pi / 180;
    final SectorShape sectorShape = SectorShape(
      center: center,
      innerRadius: innerRadius,
      outRadius: outRadius,
      startAngleRad: startAngleRad,
      sweepAngleRad: endAngleRad - startAngleRad,
    );
    // 将 sectorShape.boundingBox(); 转为 rectWidth, rectHeight 内归一化坐标
    return getNormalizedRect(
        sectorShape.boundingBox(), Rect.fromLTWH(0, 0, rectWidth, rectHeight));
  }

  // 本地完整图像内归一化坐标转视图内归一化坐标
  @override
  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;
  }

  /// 获取ROI在Urm视图中的归一化路径
  Path calRoiPathInVisual(double zoomFactor, Offset zoomOffset,
      bool isSyncDisplay, GridArea roiArea) {
    // 最小深度，最大深度，最小角度，最大角度
    final double minDepth = visualInfo.depthStart;
    final double maxDepth = visualInfo.depthEnd;
    final double minAngle = visualInfo.scanWidth / 2 * -1; // 40 / 2 * -1 = -20°
    final double maxAngle = visualInfo.scanWidth / 2; // 40 / 2 = 20°
    // 角度起点和终点
    final double startAngle =
        (roiArea.beamStart - 1) / rawBeams * (maxAngle - minAngle) + minAngle;
    final double endAngle =
        (roiArea.beamEnd - 1) / rawBeams * (maxAngle - minAngle) + minAngle;

    // 深度起点和终点
    final double startDepth =
        (roiArea.sampleStart - 1) / rawSamples * (maxDepth - minDepth) +
            minDepth;
    final double endDepth =
        (roiArea.sampleEnd - 1) / rawSamples * (maxDepth - minDepth) + minDepth;
    // 小圆半径
    final innerRadius = startDepth + visualInfo.zeroRadius;
    // 大圆半径
    final outRadius = endDepth + visualInfo.zeroRadius;
    // 图像区域宽高
    final double rectWidth = visualInfo.physicalRight - visualInfo.physicalLeft;
    final double rectHeight =
        visualInfo.physicalBottom - visualInfo.physicalTop;
    // 中心点
    final Offset center =
        visualInfo.zeroCenterOffset.scale(rectWidth, rectHeight);
    // 角度转弧度
    final double startAngleRad = (90 - startAngle) * pi / 180;
    final double endAngleRad = (90 - endAngle) * pi / 180;
    final SectorShape sectorShape = SectorShape(
      center: center,
      innerRadius: innerRadius,
      outRadius: outRadius,
      startAngleRad: startAngleRad,
      sweepAngleRad: endAngleRad - startAngleRad,
    );

    final Path sectorPath = sectorShape.formPath();
    final Rect sectorBoundry = sectorShape.boundingBox();
    // 使用 rectWidth, rectHeight 将路径归一化
    Matrix4 matrix4 = Matrix4.identity()..scale(1 / rectWidth, 1 / rectHeight);
    Path newPath = sectorPath.transform(matrix4.storage);
    if (!isSyncDisplay) {
      // 取 newPath 的外接矩形 使用 sectorBoundry .scale(1 / rectWidth, 1 / rectHeight);
      Rect boundingBox = Rect.fromLTWH(
        sectorBoundry.left / rectHeight,
        sectorBoundry.top / rectHeight,
        sectorBoundry.width / rectWidth,
        sectorBoundry.height / rectHeight,
      );
      Matrix4 boundingMatrix = Matrix4.identity()
        ..scale(1 / boundingBox.width, 1 / boundingBox.height)
        ..translate(-boundingBox.left, -boundingBox.top);
      newPath = newPath.transform(boundingMatrix.storage);
    }

    Matrix4 zoomMatrix = Matrix4.identity()
      ..scale(zoomFactor, zoomFactor)
      ..translate(
        1 / zoomFactor / 2 - zoomOffset.dx,
        1 / zoomFactor / 2 - zoomOffset.dy,
      );
    print("newPath: ${newPath.getBounds()}");
    return newPath.transform(zoomMatrix.storage);
  }
}
