import 'package:fis_jsonrpc/rpc.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.dart';
import 'package:fis_measure/interfaces/process/items/item_metas.dart';
import 'package:fis_measure/interfaces/process/workspace/point_info.dart';
import 'package:fis_measure/process/calcuators/urm_calcuators/urm_trace_den_measure.dart';
import 'package:fis_measure/process/calcuators/urm_calcuators/urm_trace_den_vel_measure.dart';
import 'package:fis_measure/process/calcuators/urm_calcuators/urm_trace_density.dart';
import 'package:fis_measure/process/calcuators/urm_calcuators/urm_trace_fractal_dim.dart';
import 'package:fis_measure/process/calcuators/urm_calcuators/urm_trace_hist.dart';
import 'package:fis_measure/process/calcuators/urm_calcuators/urm_trace_perfusion.dart';
import 'package:fis_measure/process/calcuators/urm_calcuators/urm_trace_vel_measure.dart';
import 'package:fis_measure/process/primitives/area_abstract.dart';
import 'package:fis_measure/process/primitives/trace.dart';
import 'package:fis_measure/process/primitives/utils/urm_sharp_copy.dart';
import 'package:fis_measure/utils/prompt_box.dart';
import 'package:flutter/material.dart';
import 'dart:ui' as ui;

import 'package:flutter/services.dart';

class URMTraceMeasure extends Trace {
  URMTraceMeasure(super.meta, super.parent);
  static bool needPerfusion = false;

  static URMTraceMeasure createURMTraceDensity(ItemMeta meta,
      [IMeasureItem? parent]) {
    URMTraceMeasure measureTraceDensity = URMTraceMeasure(meta, parent);
    measureTraceDensity.calculator = URMTraceDensityCal(
      measureTraceDensity,
    );
    return measureTraceDensity;
  }

  static URMTraceMeasure createURMTraceFractalDim(ItemMeta meta,
      [IMeasureItem? parent]) {
    URMTraceMeasure measureTraceFractalDim = URMTraceMeasure(meta, parent);
    measureTraceFractalDim.calculator = URMTraceFractalDimCal(
      measureTraceFractalDim,
    );
    return measureTraceFractalDim;
  }

  static URMTraceMeasure createURMTraceDenMeasure(ItemMeta meta,
      [IMeasureItem? parent]) {
    URMTraceMeasure measureTraceDen = URMTraceMeasure(meta, parent);
    measureTraceDen.calculator = URMTraceDenMeasureCal(
      measureTraceDen,
    );
    return measureTraceDen;
  }

  static URMTraceMeasure createURMTraceVelMeasure(ItemMeta meta,
      [IMeasureItem? parent]) {
    URMTraceMeasure measureTraceVel = URMTraceMeasure(meta, parent);
    measureTraceVel.calculator = URMTraceVelMeasureCal(
      measureTraceVel,
    );

    return measureTraceVel;
  }

  static URMTraceMeasure createURMTracePerfusion(ItemMeta meta,
      [IMeasureItem? parent]) {
    URMTraceMeasure measureTracePerfusion = URMTraceMeasure(meta, parent);
    measureTracePerfusion.calculator = URMTracePerfusionCal(
      measureTracePerfusion,
    );
    needPerfusion = true;
    return measureTracePerfusion;
  }

  static URMTraceMeasure createURMTraceHist(ItemMeta meta,
      [IMeasureItem? parent]) {
    URMTraceMeasure measureTraceHist = URMTraceMeasure(meta, parent);
    measureTraceHist.calculator = URMTraceHistCal(
      measureTraceHist,
    );
    return measureTraceHist;
  }

  static URMTraceMeasure createURMTraceDenVelMeasure(ItemMeta meta,
      [IMeasureItem? parent]) {
    URMTraceMeasure measureTraceDenVel = URMTraceMeasure(meta, parent);
    measureTraceDenVel.calculator = URMTraceDenVelMeasureCal(
      measureTraceDenVel,
    );

    return measureTraceDenVel;
  }

  @override
  bool onExecuteMouse(PointInfo args) {
    if (waitingResult) return false;
    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 (args.pointType == PointInfoType.mouseUp) return false;

      feature?.adopt(args);
      if (args.pointType == PointInfoType.mouseDown) {
        handleFinish();
      } else {
        checkAutoSnap(args);
      }
    }
    return true;
  }

  @override
  void handleMouseDownWhileWaiting(PointInfo args) {
    if (needPerfusion) {
      feature = TracePerfusionImageFeature(this);
    } else {
      super.handleMouseDownWhileWaiting(args);
    }
    state = ItemStates.running;
  }

  bool waitingResult = false;

  void handleFinish({bool recordSharp = true}) async {
    if (recordSharp) {
      _recordSharp();
    }

    feature!.isActive = false;
    waitingResult = true;
    await doCalculateAsync();
    doFeatureFinish();
    doFeatureUpdate(); // 若不执行,子测量将无法自动切换
    PromptBox.dismiss();
    waitingResult = false;
  }

  void _recordSharp() {
    UrmSharpCopyBoard.recordSharp(
      UrmSharpCopyDataType.trace,
      feature!.innerPoints,
    );
  }

  /// 自动结束检测
  @override
  bool checkAutoSnap(PointInfo current, [bool autoFinishFeature = true]) {
    if (feature == null || feature!.innerPoints.length < 3) {
      isSmartMove = false;
      return _syncState(false);
    }

    // final viewport = feature!.hostVisualArea!.viewport!;

    if (isAutoSnap == false) return false;
    final pixelSize = application.displaySize;

    final p1 = feature!.innerPoints.first.scale2Size(pixelSize);
    final p2 = current.scale2Size(pixelSize);
    final length = (p1 - p2).length;
    if (length > snapThreshold * 2.0 && !isSmartMove) {
      isSmartMove = true;
    }
    if (length < snapThreshold && isSmartMove) {
      feature!.innerPoints.last = feature!.innerPoints.first.clone();

      /// 此处的最后一个点,方便计算,但是绘制时要剔除
      // feature!.innerPoints.removeLast();

      HapticFeedback.heavyImpact();
      if (autoFinishFeature) {
        handleFinish();
      }
      isSmartMove = false;
      return _syncState(true);
    } else {
      return _syncState(false);
    }
  }

  bool _syncState(bool isSnap) {
    snapState = isSnap;
    return snapState;
  }
}

class TracePerfusionImageFeature extends TraceFeature {
  TracePerfusionImageFeature(AreaItemAbstract refItem) : super(refItem);

  ui.Image? perfusionImg;
  IntRect? perfusionPiexlRect;
  DPoint? leftTopPoint;
  DPoint? rightBottomPoint;
  @override
  void paint(Canvas canvas, Size size) {
    // paintPerfusion(canvas, size);
    super.paint(canvas, size);
  }

  /// 绘制灌注图
  @override
  void paintPerfusion(Canvas canvas, Size size) {
    if (perfusionImg != null) {
      Paint paint = Paint();

      Rect src = Rect.fromLTWH(
        0,
        0,
        perfusionImg!.width.toDouble(),
        perfusionImg!.height.toDouble(),
      );
      if (leftTopPoint == null || rightBottomPoint == null) {
        return;
      }
      DPoint leftTop = convert2ViewPoint(size, leftTopPoint!);
      DPoint rightBottom = convert2ViewPoint(size, rightBottomPoint!);
      convert2ViewPoint(size, rightBottomPoint!);
      Rect dst = Rect.fromPoints(
          Offset(leftTop.x, leftTop.y), Offset(rightBottom.x, rightBottom.y));
      canvas.drawImageRect(perfusionImg!, src, dst, paint);
    }
  }
}