import 'dart:ui';
import 'dart:math' as math;

import 'package:fis_measure/interfaces/date_types/point.dart';
import 'package:fis_measure/interfaces/date_types/rect_region.dart';
import 'package:fis_measure/interfaces/date_types/vector.dart';
import 'package:fis_measure/interfaces/enums/items.dart';
import 'package:fis_measure/interfaces/process/items/item.dart';
import 'package:fis_measure/interfaces/process/items/item_metas.dart';
import 'package:fis_measure/interfaces/process/items/types.dart';
import 'package:fis_measure/interfaces/process/workspace/application.dart';
import 'package:fis_measure/interfaces/process/workspace/point_info.dart';
import 'package:fis_measure/process/calcuators/velocity.dart';
import 'package:fis_measure/process/visual/tissue_area.dart';
import 'package:fis_measure/utils/canvas.dart';
import 'package:get/get.dart';
import 'package:vid/us/vid_us_mode.dart';
import 'package:vid/us/vid_us_probe.dart';

import '../calcuators/depth.dart';
import '../items/item.dart';
import '../items/item_feature.dart';
import '../physical_coordinates/convex_tissue.dart';

class Location extends MeasureItem<LocationFeature> {
  Location(ItemMeta meta, IMeasureItem? parent) : super(meta, parent);

  @override
  bool get finishAfterUnactive => false;

  @override
  bool onExecuteMouse(PointInfo args) {
    if (state == ItemStates.finished || state == ItemStates.waiting) {
      if (args.pointType == PointInfoType.mouseMove) {
        handleMouseMoveWhileFinish(args);
      }
    }
    if (state == ItemStates.running) {
      if (args.pointType == PointInfoType.mouseUp) return false;

      feature?.point = args;
      doCalculate();
      if (args.pointType == PointInfoType.mouseDown) {
        doFeatureFinish();
      }
    }
    return true;
  }

  String mapPointInfoType(PointInfoType type) {
    switch (type) {
      case PointInfoType.mouseUp:
        return '⬆️';
      case PointInfoType.mouseDown:
        return '⬇️';
      case PointInfoType.mouseMove:
        return '⭐';
      case PointInfoType.touchUp:
        return '⬆️';
      case PointInfoType.touchDown:
        return '⬇️';
      case PointInfoType.touchMove:
        return '⭐';
    }
  }

  @override
  bool onExecuteTouch(PointInfo args) {
    if (state == ItemStates.finished || state == ItemStates.waiting) {
      if (args.pointType == PointInfoType.touchDown) {
        handleMouseMoveWhileFinish(args);
      }
    }
    if (state == ItemStates.running) {
      if (args.pointType == PointInfoType.touchDown) {
        feature?.point = args;
        doCalculate();
      }
      if (args.pointType == PointInfoType.touchMove) {
        args.addOffset(0, -0.2);
        if (isMoveTargetOutOfRange(args)) return true;
        feature?.point = args;
        doCalculate();
      }
      if (args.pointType == PointInfoType.touchUp) {
        doFeatureFinish();
      }
    }
    return true;
  }

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

  void handleTissueTM(VidUsModeType mode, DPoint point) {
    if (mode == VidUsModeType.TissueTM || mode == VidUsModeType.Doppler) {
      feature = LocationFeature(this, point);
    }
  }

  void handleTissue(PointInfo args, DPoint point) {
    final mode = args.hostVisualArea!.mode.modeType;
    if (mode == VidUsModeType.Tissue || mode == VidUsModeType.Flow) {
      final isProbeConvex = (args.hostVisualArea! as TissueArea).isConvex;
      if (isProbeConvex) {
        feature = TissueConvexLocationFeature(this, point);
      } else {
        feature = LocationFeature(this, point);
      }
    }
  }

  static Location createTissueConvexDepth(
    ItemMeta meta, [
    IMeasureItem? parent,
  ]) {
    Location location = Location(meta, parent);
    location.calculator = TissueConvexDepthCal(location);
    return location;
  }

  static Location createTissueDepth(
    ItemMeta meta, [
    IMeasureItem? parent,
  ]) {
    final area = Get.find<IApplication>().currentVisualArea;
    final isProbeConvex = (area as TissueArea).isConvex;
    final fn =
        isProbeConvex ? createTissueConvexDepth : createTissueNormalDepth;
    return fn(meta, parent);
  }

  static Location createTissueNormalDepth(
    ItemMeta meta, [
    IMeasureItem? parent,
  ]) {
    Location location = Location(meta, parent);
    location.calculator = TissueDepthCal(location);
    return location;
  }

  static Location createTissueTMDepth(
    ItemMeta meta, [
    IMeasureItem? parent,
  ]) {
    Location location = Location(meta, parent);
    location.calculator = MDepthCal(location);
    return location;
  }

  static Location createVelocity(
    ItemMeta meta, [
    IMeasureItem? parent,
  ]) {
    Location location = Location(meta, parent);
    location.calculator = VelocityCal(location);
    return location;
  }
}

class TissueConvexLocationFeature extends LocationFeature {
  TissueConvexLocationFeature(IMeasureItem refItem, DPoint point)
      : super(refItem, point);

  @override
  void paint(Canvas canvas, Size size) {
    super.paint(canvas, size);
    if (!measureData.measureSystemSetting.showDepthGuideline) return;
    final point = this.point.clone();

    final layout = hostVisualArea!.displayRegion;
    point.addOffset(-layout.left, -layout.top);
    // TODO : fix bug

    final viewport = hostVisualArea!.viewport!;
    final physical = (viewport.physical! as ConvexTissuePhysicalCoordinate);
    final region = viewport.region;

    final physicalZeroPoint =
        DPoint(region.width / 2, physical.zeroY); // 真实尺寸圆心

    final physicalPoint = viewport.convert(point);
    final physicalStartPoint = _findCrossPointOnInnerDiameter(
      physicalZeroPoint,
      physicalPoint,
      physical.zeroRadius,
      viewport.region,
    );

    // 在内圈内,不处理
    if (physicalStartPoint == null) return;

    final logicStartPoint = viewport.convertBack(physicalStartPoint);
    logicStartPoint.addOffset(layout.left, layout.top);
    point.addOffset(layout.left, layout.top);
    Offset viewStartPoint = convert2ViewPoint(size, logicStartPoint).toOffset();
    Offset viewPoint = convert2ViewPoint(size, point).toOffset();

    if (viewStartPoint.dy < 0) {
      // TODO: 处理起点在画布区间外的情况,区间外不绘制
      return;
    }

    canvas.drawDashLine(viewStartPoint, viewPoint, 1, 10, paintLinePan);
  }

  /// 找到直线(圆心到当前点)和扇形内圈的交叉点
  DPoint? _findCrossPointOnInnerDiameter(
    DPoint zero,
    DPoint point,
    double zeroRadius,
    RectRegion region,
  ) {
    final centerOfX = region.width / 2;
    final pointWidthOnX = centerOfX - point.x;
    final pointHeightOnY = point.y - zero.y;
    final pointRadius =
        math.sqrt(math.pow(pointWidthOnX, 2) + math.pow(pointHeightOnY, 2));
    final ratio = zeroRadius / pointRadius;
    if (ratio > 1) return null;

    double width = pointWidthOnX * ratio;
    double height = pointHeightOnY * ratio;
    double x = centerOfX - width;
    double y = height + zero.y;
    return DPoint(x, y);
  }
}

class LocationFeature extends MeasureItemFeature {
  LocationFeature(IMeasureItem refItem, DPoint point) : super(refItem) {
    innerPoints.add(point);
  }

  DPoint get point => innerPoints[0];
  set point(DPoint value) => innerPoints[0] = value;

  @override
  void paint(Canvas canvas, Size size) {
    drawId(canvas, size);
    final viewPoint = convert2ViewPoint(size, point).toOffset();
    drawVertex(canvas, viewPoint, isActive);
  }
}