import 'dart:math';
import 'dart:ui';
import 'package:vector_math/vector_math.dart';
import 'package:fis_measure/interfaces/date_types/point.dart';
import 'package:fis_measure/interfaces/enums/items.dart';
import 'package:fis_measure/interfaces/process/items/item_metas.dart';
import 'package:fis_measure/interfaces/process/items/item.dart';
import 'package:fis_measure/interfaces/process/items/types.dart';
import 'package:fis_measure/interfaces/process/workspace/point_info.dart';
import 'package:fis_measure/process/calcuators/calculator.dart';
import 'package:fis_measure/process/items/item.dart';
import 'package:fis_measure/process/items/item_feature.dart';

/// 独立的两个线段确定一个角度
class TwolineAngle extends MeasureItem<TwolineAngleFeature> {
  TwolineAngle(ItemMeta meta, IMeasureItem? parent) : super(meta, parent);

  static TwolineAngle createTwolineAngle(ItemMeta meta,
      [IMeasureItem? parent]) {
    TwolineAngle polygon = TwolineAngle(meta, parent);
    polygon.calculator = _AngleCalc(polygon);
    return polygon;
  }

  @override
  bool onExecuteMouse(PointInfo args) {
    if (state == ItemStates.finished) {
      if (args.pointType == PointInfoType.mouseDown) {
        state = ItemStates.waiting;
      }
    }

    if (state == ItemStates.waiting) {
      if (args.pointType == PointInfoType.mouseDown) {
        handleMouseDownWhileWaiting(args);
      }
    } else if (state == ItemStates.running) {
      if (feature == null) return false;
      if (args.pointType == PointInfoType.mouseUp) return false;

      final f = feature!;

      if (args.pointType == PointInfoType.mouseDown) {
        f.innerPoints.add(args);
        if (f.innerPoints.length == 5) {
          f.innerPoints.removeLast();
          doFeatureFinish();
        }
      } else {
        f.innerPoints.last = args;
      }
      doCalculate();
    }
    return true;
  }

  DPoint lastStartPoint = DPoint(0, 0); // 上一个起点
  bool isFirstPointNeedOffset = false; // 第一个点是否需要施加偏移
  DPoint splineTouchStartPoint = DPoint(0, 0); // 轨迹触摸起始点
  bool isOtherPointNeedOffset = false; // 其他点是否需要施加偏移
  @override
  bool onExecuteTouch(PointInfo args) {
    if (state == ItemStates.finished) {
      if (args.pointType == PointInfoType.touchDown) {
        state = ItemStates.waiting;
      }
    }

    if (state == ItemStates.waiting) {
      if (isFirstPointNeedOffset) args.addOffset(0, -0.2);
      switch (args.pointType) {
        case PointInfoType.touchDown:
          handleTouchDownWhileWaiting(args);
          isFirstPointNeedOffset = false;
          break;
        case PointInfoType.touchUp:
          lastStartPoint = args; // 设置线段起点
          state = ItemStates.running;
          feature?.innerPoints.first = args;
          break; // 按下立即抬起无事发生
        case PointInfoType.touchMove:
          if (isMoveTargetOutOfRange(args)) return true;

          isFirstPointNeedOffset = true;
          feature?.innerPoints.first = args;
          break;
        default:
          break;
      }
    } else if (state == ItemStates.running) {
      final f = feature!;
      if (isOtherPointNeedOffset && f.innerPoints.length == 3) {
        args.addOffset(0, -0.2);
      }
      if (feature == null) return false;
      PointInfo newPoint = PointInfo.fromOffset(
          lastStartPoint
              .clone()
              .addVector(args - splineTouchStartPoint)
              .toOffset(),
          args.pointType);
      newPoint.hostVisualArea = args.hostVisualArea;
      if (args.pointType == PointInfoType.touchUp) {
        if (!isOtherPointNeedOffset) {
          f.innerPoints.last = args;
          lastStartPoint = args;
          doCalculate();
        } else {
          lastStartPoint = newPoint;
        }
        if (f.innerPoints.length == 4) {
          doFeatureFinish();
        }
      }

      if (args.pointType == PointInfoType.touchDown) {
        isOtherPointNeedOffset = false;
        splineTouchStartPoint = args;
        f.innerPoints.add(lastStartPoint);
        if (f.innerPoints.length == 3) {
          lastStartPoint = args;
        }
      }
      if (args.pointType == PointInfoType.touchMove) {
        if (isMoveTargetOutOfRange(newPoint)) return true;

        isOtherPointNeedOffset = true;
        f.innerPoints.last = newPoint;
      }
      doCalculate();
    }
    return true;
  }

  void handleMouseDownWhileWaiting(PointInfo args) {
    // TODO: 判断是否当前area
    // 转换为Area逻辑位置
    final point = args.toAreaLogicPoint();
    feature = TwolineAngleFeature(this, point);
    if (args.hostVisualArea != null) {
      feature!.hostVisualArea = args.hostVisualArea;
    }
    state = ItemStates.running;
  }

  void handleTouchDownWhileWaiting(PointInfo args) {
    // TODO: 判断是否当前area
    // 转换为Area逻辑位置
    final point = args.toAreaLogicPoint();
    feature = TwolineAngleFeature.withOneStartPoint(this, point);
    if (args.hostVisualArea != null) {
      feature!.hostVisualArea = args.hostVisualArea;
    }
  }
}

class TwolineAngleFeature extends MeasureItemFeature {
  TwolineAngleFeature(IMeasureItem refItem, DPoint point) : super(refItem) {
    innerPoints.add(point.clone());
    innerPoints.add(point.clone());
  }
  TwolineAngleFeature.withOneStartPoint(IMeasureItem refItem, DPoint point)
      : super(refItem) {
    innerPoints.add(point.clone());
  }
  @override
  void paint(Canvas canvas, Size size) {
    if (innerPoints.isEmpty) return;
    drawId(canvas, size);
    final innerOffsets =
        innerPoints.map((e) => convert2ViewPoint(size, e).toOffset()).toList();
    final len = innerOffsets.length;

    if (len == 1) {
      drawVertex(canvas, innerOffsets[0]);
    } else if (len == 2) {
      final a = innerOffsets[0];
      final b = innerOffsets[1];
      canvas.drawLine(a, b, paintLinePan);
    } else if (len == 3) {
      final a = innerOffsets[0];
      final b = innerOffsets[1];
      canvas.drawLine(a, b, paintLinePan);
      drawVertex(canvas, innerOffsets[2]);
    } else if (len == 4) {
      final a = innerOffsets[0];
      final b = innerOffsets[1];
      final c = innerOffsets[2];
      final d = innerOffsets[3];
      canvas.drawLine(a, b, paintLinePan);
      canvas.drawLine(c, d, paintLinePan);
      //向量 A、B
      final vecA = Vector2(b.dx - a.dx, b.dy - a.dy);
      final vecB = Vector2(d.dx - c.dx, d.dy - c.dy);
      //计算向量夹角
      final angle = vecA.angleToSigned(vecB);
      //计算射线cd的角度
      final vecBAngle = vecB.angleToSigned(Vector2(1, 0));
      // 计算射线ab与射线cd的交点
      final Offset? p = _getIntersection(a, b, c, d);
      if (p != null) {
        // 绘制角度
        canvas.drawArc(Rect.fromCircle(center: p, radius: 30), -vecBAngle,
            -angle, false, paintLinePan);
        //如果交点在线段外,线段要延长至交点
        Offset? p1 = _getIntersection(a, b, p, Offset(0, p.dy));
        if (p1 != null) {
          final vecA1 = Vector2(p1.dx - a.dx, p1.dy - a.dy).normalized() * 50;
          p1 += Offset(vecA1.x, vecA1.y);
          canvas.drawLine(a, p1, paintLinePan);
        }
        Offset? p2 = _getIntersection(c, d, p, Offset(0, p.dy));
        if (p2 != null) {
          final vecB1 = Vector2(p2.dx - c.dx, p2.dy - c.dy).normalized() * 50;
          p2 += Offset(vecB1.x, vecB1.y);
          canvas.drawLine(c, p2, paintLinePan);
        }
      }
    }
  }

  /// 计算射线ab与射线cd的交点
  Offset? _getIntersection(Offset a, Offset b, Offset c, Offset d) {
    final x1 = a.dx;
    final y1 = a.dy;
    final x2 = b.dx;
    final y2 = b.dy;
    final x3 = c.dx;
    final y3 = c.dy;
    final x4 = d.dx;
    final y4 = d.dy;

    final denominator = ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4));

    // 检查分母是否为零,即两条射线是否平行
    if (denominator == 0) {
      return null; // 无交点
    }

    final x =
        ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) /
            denominator;
    final y =
        ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) /
            denominator;

    return Offset(x, y);
  }
}

class _AngleCalc extends Calculator<TwolineAngle, double> {
  _AngleCalc(TwolineAngle ref) : super(ref);

  @override
  void calculate() {
    if (ref.feature == null) return;

    final feature = ref.feature!;
    final viewport = feature.hostVisualArea!.viewport!;
    final points = feature.innerPoints.map((e) => viewport.convert(e)).toList();

    feature.values.clear();

    double angle;
    if (points.length != 4) {
      angle = 0;
    } else {
      angle = calcAngle(points[0], points[1], points[2], points[3]);
    }
    for (var output in ref.meta.outputs) {
      if (output.name == MeasureTypes.Angle) {
        var value = roundDouble(angle, output.fractionalDigits);
        feature.updateFloatValue(output, value, output.unit);
      }
    }
  }

  static double calcAngle(
      DPoint pointsA, DPoint pointsB, DPoint pointsC, DPoint pointsD) {
    double finalAngleDegree = 0;
    //向量 A、B
    final vecA = Vector2(pointsB.x - pointsA.x, pointsB.y - pointsA.y);
    final vecB = Vector2(pointsD.x - pointsC.x, pointsD.y - pointsC.y);
    //计算向量夹角
    final angle = vecA.angleToSigned(vecB);
    //转换为角度
    finalAngleDegree = angle * 180 / pi;
    if (finalAngleDegree < 0) {
      finalAngleDegree = -finalAngleDegree;
    }
    return finalAngleDegree;
  }
}