// ignore_for_file: constant_identifier_names

import 'dart:math' as math;
import 'package:fis_measure/interfaces/date_types/point.dart';
import 'package:fis_measure/interfaces/enums/annotation.dart';
import 'package:fis_measure/interfaces/process/workspace/application.dart';
import 'package:fis_measure/interfaces/process/workspace/point_info.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';

import 'annotation.dart';

/// 箭头注释
class ArrowAnnotation extends AnnotationItem<ArrowAnnotationItemFeature> {
  ArrowAnnotation() : super(AnnotationType.arrow);

  @override
  bool onExecuteMouse(PointInfo args) {
    if (state == AnnotationStates.finish) {
      state = AnnotationStates.waiting;
    }
    if (state == AnnotationStates.waiting) {
      if (args.pointType == PointInfoType.mouseDown) {
        feature = ArrowAnnotationItemFeature(this, args);
        state = AnnotationStates.running;
        return true;
      } else {
        return false;
      }
    } else {
      if (args.pointType == PointInfoType.mouseUp) return false;

      feature?.endPoint = args;
      if (args.pointType == PointInfoType.mouseDown) {
        doFeatureFinish();
      }
    }

    return true;
  }

  PointInfo? startPoint;
  @override
  bool onExecuteTouch(PointInfo args) {
    if (state == AnnotationStates.finish) {
      if (args.pointType == PointInfoType.touchDown) {
        state = AnnotationStates.waiting;
      }
    }
    if (state == AnnotationStates.waiting) {
      switch (args.pointType) {
        case PointInfoType.touchDown:
          startPoint = args; // 设置线段起点
          break;
        case PointInfoType.touchUp:
          break; // 按下立即抬起无事发生
        case PointInfoType.touchMove:
          feature = ArrowAnnotationItemFeature(this, startPoint as DPoint);
          state = AnnotationStates.running; // 通过设置的起点开始一个绘制事件
          break;
        default:
          break;
      }
    } else if (state == AnnotationStates.running) {
      if (args.pointType == PointInfoType.touchUp) {
        doFeatureFinish();
      }
      if (args.pointType == PointInfoType.touchMove) {
        feature?.endPoint = args;
      }
    }
    // if (state == AnnotationStates.waiting) {
    //   if (args.pointType == PointInfoType.mouseDown) {
    //     feature = ArrowAnnotationItemFeature(this, args);
    //     state = AnnotationStates.running;
    //     return true;
    //   } else {
    //     return false;
    //   }
    // } else {
    //   if (args.pointType == PointInfoType.mouseUp) return false;

    //   feature?.endPoint = args;
    //   if (args.pointType == PointInfoType.mouseDown) {
    //     doFeatureFinish();
    //   }
    // }

    return true;
  }
}

class ArrowAnnotationItemFeature extends AnnotationItemFeature {
  static const C_ARRPW_ANGLE = 90.0; // 箭头角度
  static const C_ARROW_LENGTH = 8.0; // 中心线交叉点到终点的长度
  final _paint = Paint()
    ..color = Colors.yellow
    ..strokeWidth = 2
    ..style = PaintingStyle.stroke;

  ArrowAnnotationItemFeature(ArrowAnnotation ref, DPoint offset) : super(ref) {
    points.addAll([offset]);
  }

  DPoint get endPoint => points[1];
  set endPoint(DPoint value) {
    if (points.length > 1) {
      points[1] = value;
    } else {
      points.add(value);
    }
  }

  DPoint get startPoint => position;

  @override
  void paint(Canvas canvas, Size size) {
    double arrowLen =
        C_ARROW_LENGTH * Get.find<IApplication>().displayScaleRatio;

    final startOffset = startPoint.scale2Size(size).toOffset();
    final Offset endOffset;
    if (points.length < 2 || startPoint == endPoint) {
      endOffset = startOffset - const Offset(0, -1);
    } else {
      endOffset = points[1].scale2Size(size).toOffset();
    }

    canvas.drawLine(startOffset, endOffset, _paint);

    _drawArrow(canvas, startOffset, endOffset, arrowLen);
  }

  /// 绘制箭头
  void _drawArrow(Canvas canvas, Offset p1, Offset p2, double arrowLength) {
    final directionX = (p2.dx - p1.dx); // X轴向量方向
    final directionY = (p2.dy - p1.dy); // Y轴向量方向
    final center = _findArrowHeadCenter(p1, p2, arrowLength);

    const cuspAngle = C_ARRPW_ANGLE / 2; // 边线和中心线的角度
    const cuspRadians = cuspAngle * (math.pi / 180);
    // 边角到中心交叉点的距离
    final distanceCenter2Side = math.tan(cuspRadians) * arrowLength;

    final tan2AxisX = (p2.dy - p1.dy) / (p2.dx - p1.dx);
    // 中心线到X轴的弧度
    final radians2AxisX = math.atan(tan2AxisX).abs();

    // 在画布正坐标计算边点
    // 边点到X轴的距离
    final distance2AxisX = math.sin(radians2AxisX) * distanceCenter2Side;
    // 边点到Y轴的距离
    final distance2AxisY = math.cos(radians2AxisX) * distanceCenter2Side;

    double xRight = 0, yRight = 0;
    double xLeft = 0, yLeft = 0;
    if (directionX < 0) {
      if (directionY > 0) {
        // 右上->左下
        xRight = center.dx - distance2AxisX;
        yRight = center.dy - distance2AxisY;
        xLeft = center.dx + distance2AxisX;
        yLeft = center.dy + distance2AxisY;
      } else {
        // 右下->左上
        xRight = center.dx + distance2AxisX;
        yRight = center.dy - distance2AxisY;
        xLeft = center.dx - distance2AxisX;
        yLeft = center.dy + distance2AxisY;
      }
    } else {
      if (directionY > 0) {
        // 左上->右下
        xRight = center.dx - distance2AxisX;
        yRight = center.dy + distance2AxisY;
        xLeft = center.dx + distance2AxisX;
        yLeft = center.dy - distance2AxisY;
      } else {
        // 左下->右上
        xRight = center.dx + distance2AxisX;
        yRight = center.dy + distance2AxisY;
        xLeft = center.dx - distance2AxisX;
        yLeft = center.dy - distance2AxisY;
      }
    }

    final leftSidePoint = Offset(xLeft, yLeft);
    final rightSidePoint = Offset(xRight, yRight);
    canvas.drawLine(p2, leftSidePoint, _paint);
    canvas.drawLine(p2, rightSidePoint, _paint);
  }

  /// 找到箭头底部(两个边角的水平线)与直线的交叉点
  Offset _findArrowHeadCenter(Offset p1, Offset p2, double arrowLength) {
    final x1 = p1.dx, x2 = p2.dx;
    final y1 = p1.dy, y2 = p2.dy;
    // - 假设交叉点: p3 = (x3,y3)
    // ratio = distanc(p3-p2)/distance(p2-p1)
    // - 同时
    // ratio == (x3-x2)/(x1-x2)
    // ratio == (y3-y2)/(y1-y2)
    // - 可得
    // x3 = (x1-x2)*ratio + x2
    // y3 = (y1-y2)*ratio + y2
    final lineLength = (p2 - p1).distance;
    final ratio = arrowLength / lineLength;
    final dx = (ratio * (x1 - x2)) + x2;
    final dy = (ratio * (y1 - y2)) + y2;
    return Offset(dx, dy);
  }
}