import { PolygonsAttrib, PolygonsPointAttrib } from "@/request/type";
import {
  incEntitysFactoryGenerate,
  Attrib,
  wholeLineStyle,
  getRealAbsoluteSize,
  PenEditWholeLine,
  WholeLinePoint,
  getWholeLinePolygonPoints,
  shapeParentsEq,
  openEntityDrag,
  WholeLineInc,
  // wholeLineDelLineByPointIds,
} from "drawing-board";
import { Group } from "konva/lib/Group";
import { Path } from "konva/lib/shapes/Path";
import { Circle } from "konva/lib/shapes/Circle";
import { Label, Tag } from "konva/lib/shapes/Label";
import { Text } from "konva/lib/shapes/Text";
import { ref } from "vue";
import mitt from "mitt";
import { point } from "@/submodule/src/board/packages/whole-line/style";

// 加点
const getPolygonPoint = (position: number[]) => {
  const pointAttrib = {
    rtk: false,
    title: "",
    x: position[0],
    y: position[1],
  };
  return pointAttrib;
};

const pointActShapeFactory = (attrib: PolygonsPointAttrib, tree: any) => {
  const polygons = tree.parent as Polygons;
  const size = { width: 43, height: 44 };
  const out = new Path({
    data: `M22 44C32.6667 33.891 38 25.891 38 20C38 11.1634 30.8366 4 22 4C13.1634 4 6 11.1634 6 20C6 25.891 11.3333 33.891 22 44Z`,
    strokeScaleEnabled: true,
    stroke: "#ffffff",
    strokeWidth: 1,
  });
  const inner = new Path({
    fill: "#fff",
    data: `M22 30C27.5228 30 32 25.5228 32 20C32 14.4772 27.5228 10 22 10C16.4772 10 12 14.4772 12 20C12 25.5228 16.4772 30 22 30Z`,
  });
  const rect = new Circle({
    name: "anchor-move",
    radius: Math.min(size.width, size.height) / 2,
    fill: "rgba(0, 0, 0, 0)",
    offset: { x: -size.width / 2, y: -size.height / 2 },
  });
  const wlp = wholeLineStyle.pointShapeFactory();
  point.radius = 5;

  point.hitStrokeWidth = point.strokeWidth = 4;
  wlp.shape.name("anchor-point");

  const index = new Text({
    name: "text",
    text: `1`,
    fontFamily: "Calibri",
    fontSize: 12,
    padding: 5,
    offsetY: -8,
    fill: "#000",
  });

  const label = new Label({
    visible: false,
    opacity: 0.75,
    name: "label",
    offsetX: -size.width / 2,
    offsetY: -6,
  });

  label.add(
    new Tag({
      name: "tag",
      fill: "rgba(255, 255, 255, 0.8)",
      pointerDirection: "down",
      pointerWidth: 5,
      pointerHeight: 5,
      lineJoin: "round",
      shadowColor: "black",
      shadowBlur: 10,
      shadowOffsetX: 10,
      shadowOffsetY: 10,
      shadowOpacity: 0.5,
    }),
    new Text({
      name: "text",
      text: attrib.title || `P${attrib.id}`,
      fontFamily: "Calibri",
      fontSize: 10,
      padding: 5,
      fill: "#000",
    })
  );

  const offsetGroup = new Group();
  offsetGroup.add(out, inner, rect, label, index);
  offsetGroup.x(-size.width / 2);
  offsetGroup.y(-size.height);

  const group = new Group();
  group.add(offsetGroup, wlp.shape);

  const activeNdx = () => {
    if (polygons.editPolygonId.value) {
      const points = getWholeLinePolygonPoints(
        polygons.attrib,
        polygons.editPolygonId.value
      ).map(({ id }) => id);
      const ndx = points.indexOf(attrib.id);
      return ndx;
    }
    return -1;
  };

  const setStyle = () => {
    let [width, height] = getRealAbsoluteSize(group, [1, 1]);
    group.scale({ x: width, y: height });
    const ndx = activeNdx();
    if (~ndx) {
      index.text((ndx + 1).toString()).visible(true);
      index.offsetX(-rect.width() / 2 + index.width() / 2);
    } else {
      index.visible(false);
    }
  };

  const commonStyle = () => {
    out.fill(attrib.rtk ? "rgba(230, 162, 60, 1)" : "#409EFF");
    label.visible(false);
    wlp.common();
  };

  const result = {
    shape: group,
    common: commonStyle,
    hover: () => {
      label.visible(true);
    },
    setData(data: number[]) {
      setStyle();
      group.x(data[0]);
      group.y(data[1]);

      label.visible(polygons.activePointId.value === attrib.id);
    },
    draging() {
      if (polygons.editPolygonId.value && !attrib.rtk) {
        out.fill("#e0403c");
      }
    },
    active() {
      polygons.activePointId.value = attrib.id;
      polygons.bus.emit("clickPoint", attrib);
    },
  };

  return result;
};

export class Polygons extends PenEditWholeLine<PolygonsAttrib & Attrib> {
  bus = mitt<{ clickPoint: PolygonsPointAttrib; penEndHandler: void }>();
  activePointId = ref<string>();

  dragAttach(inc: WholeLineInc<PolygonsAttrib & Attrib>) {
    inc.pointEntityInc.adds.forEach((point) => {
      openEntityDrag(point, {
        readyHandler: (attrib) => {
          return [attrib.x, attrib.y];
        },
        moveHandler: (pointAttrib, move) => {
          if (this.editPolygonId.value && !pointAttrib.rtk) {
            pointAttrib.x = move[0];
            pointAttrib.y = move[1];
          }
        },
      });
      point.enableMouseAct(point.actShape);
    });

    inc.lineEntityInc.adds.forEach((line) => {
      line.enableMouseAct(line.actShape);
    });

    inc.polygonEntityInc.adds.forEach((py) => {
      py.enableMouseAct(py.actShape);
    });
  }

  removePolygon(polygonId: string) {
    const ndx = this.attrib.polygons.findIndex(({ id }) => id === polygonId);
    if (!~ndx) {
      return;
    }
    const polygonLines = this.attrib.polygons[ndx].lineIds;
    let joinPointIds: string[] = [];

    while (polygonLines.length) {
      const ndx = this.attrib.lines.findIndex(
        ({ id }) => id === polygonLines[0]
      );
      if (~ndx) {
        joinPointIds.push(...this.attrib.lines[ndx].pointIds);
        this.attrib.lines.splice(ndx, 1);
      }
      polygonLines.shift();
    }

    joinPointIds = Array.from(new Set(joinPointIds));
    while (joinPointIds.length) {
      const ndx = this.attrib.points.findIndex(
        ({ id }) => id === joinPointIds[0]
      );

      if (~ndx && !this.attrib.points[ndx].rtk) {
        this.attrib.points.splice(ndx, 1);
      }
      joinPointIds.shift();
    }

    this.attrib.polygons.splice(ndx, 1);
  }

  initIncFactory() {
    super.initIncFactory();
    this.incPointsFactory = incEntitysFactoryGenerate(
      WholeLinePoint<any>,
      this,
      (point) => {
        point.actShapeFactory = pointActShapeFactory;
      }
    );
  }

  editPolygon(polygonId?: string) {
    super.enterEditMode({
      polygonId: polygonId,
      pointAttribFactory: getPolygonPoint,
      canOper: (tree, operShape) => {
        return (
          !tree.name.includes(WholeLinePoint.namespace) ||
          operShape.name() === "anchor-point"
        );
      },
      quitHandler: () => {
        this.bus.emit("penEndHandler");
      },
      canDelPoint: (p) => !p.rtk,
      quotePoint: false,
    });
    return super.leaveEditMode;
  }

  mounted(): void {
    super.mounted();
    let clearCursor: (() => void) | null = null;
    this.container.stage.on("mousemove.anchor-move", (evt) => {
      const isPoint = evt.target.name() === "anchor-move";
      if (!isPoint) {
        clearCursor && clearCursor();
        clearCursor = null;
        return;
      }

      if (this.editPolygonId.value) {
        clearCursor = this.container.setCursor("move");
      } else {
        clearCursor = this.container.setCursor("pointer");
      }
    });

    this.container.stage.on("click.anchor-move", (evt) => {
      const point = shapeParentsEq(evt.target, (shape) =>
        shape.id().startsWith(WholeLinePoint.namespace)
      );
      if (!point) {
        this.activePointId.value = undefined;
      }
    });
  }
  destory(): void {
    super.destory();
    this.container.stage.off("mousemove.anchor-move click.anchor-move");
  }
}
