<template>
  <EditLine
    :ref="(d: any) => shape = d?.shape"
    :data="{ ...line, ...style, lineJoin: 'miter' }"
    :opacity="0"
    :points="points"
    :closed="false"
    :id="line.id"
    :disablePoint="!canEdit || mode.include(Mode.readonly)"
    :ndx="0"
    @dragstart="emit('dragLineStart', props.line)"
    @update:line="(ps) => emit('dragLine', props.line, ps)"
    @dragend="emit('dragLineEnd', props.line)"
    @add-point="addPoint"
  />

  <SizeLine
    v-if="
      status.active ||
      config.showComponentSize ||
      isDrawIng ||
      dragPointIds?.includes(line.a) ||
      dragPointIds?.includes(line.b)
    "
    :points="points"
    :strokeWidth="style.strokeWidth"
    :stroke="style.stroke"
  />

  <v-line
    v-for="polygon in diffPolygons"
    :config="{
      points: flatPositions(polygon),
      fill: line.stroke,
      closed: true,
      listening: false,
    }"
    v-if="diffPolygons"
  />
  <template v-if="showEditPoint">
    <EditPoint
      v-for="(point, ndx) in points"
      :key="point.id"
      :size="line.strokeWidth"
      :points="points"
      :opacity="1"
      :drawIng="ndx === 0 && isDrawIng"
      :ndx="ndx"
      :closed="false"
      :id="line.id"
      :disable="addMode"
      :color="isDrawIng ? themeColor : style.stroke"
      @dragstart="dragstartHandler([point.id])"
      @update:position="(p) => emit('updatePoint', { ...point, ...p })"
      @dragend="dragendHandler"
      @delete="delPoint(point)"
    />
  </template>

  <PropertyUpdate
    :describes="describes"
    :data="line"
    :target="shape"
    :name="shapeName"
    @change="
      () => {
        isStartChange || emit('updateBefore', []);
        emit('updateLine', { ...line });
        emit('update');
        isStartChange = false;
      }
    "
    @delete="delHandler"
  />
  <Operate :target="shape" :menus="menus" />
</template>

<script lang="ts" setup>
import { computed, ref, watchEffect } from "vue";
import { getMouseStyle, getSnapInfos, LineData, shapeName } from "./index.ts";
import { flatPositions, onlyId } from "@/utils/shared.ts";
import EditLine from "../share/edit-line.vue";
import { getVectorLine, lineCenter, lineLen, lineVector, Pos } from "@/utils/math.ts";
import { Line } from "konva/lib/shapes/Line";
import { DC } from "@/deconstruction.js";
import { useMode } from "@/core/hook/use-status.ts";
import { Mode } from "@/constant/mode.ts";
import SizeLine from "../share/size-line.vue";
import { useConfig } from "@/core/hook/use-config.ts";
import { ComponentSnapInfo } from "../index.ts";
import { useCustomSnapInfos } from "@/core/hook/use-snap.ts";
import { mergeDescribes } from "@/core/html-mount/propertys/index.ts";
import { PropertyUpdate, Operate } from "../../html-mount/propertys/index.ts";
import {
  useAnimationMouseStyle,
  useMouseShapeStatus,
} from "@/core/hook/use-mouse-status.ts";
import { themeColor } from "@/constant";
import { Vector2 } from "three";
import { useGetDiffPolygons, useGetExtendPolygon } from "./attach-view.ts";
import EditPoint from "../share/edit-point.vue";

const mode = useMode();

const props = defineProps<{
  line: LineData["lines"][number];
  addMode?: boolean;
  canEdit?: boolean;
  data: LineData;
  dragPointIds?: string[];
}>();

const getExtendPolygon = useGetExtendPolygon();
const polygon = computed(() =>
  getExtendPolygon(props.data, props.line, !showEditPoint.value)
);
const getDiffPolygons = useGetDiffPolygons();
const diffPolygons = computed(() => getDiffPolygons(polygon.value));
const showEditPoint = computed(
  () => (!mode.include(Mode.readonly) && props.canEdit) || isDrawIng.value
);

const emit = defineEmits<{
  (e: "updatePoint", value: LineData["points"][number]): void;
  (e: "addPoint", value: LineData["points"][number]): void;
  (e: "delPoint", value: LineData["points"][number]): void;
  (e: "delLine"): void;
  (e: "updateLine", value: LineData["lines"][number]): void;
  (e: "updateBefore", value: string[]): void;
  (e: "update"): void;

  (e: "dragLineStart", value: LineData["lines"][number]): void;
  (e: "dragLine", line: LineData["lines"][number], move: Pos[]): void;
  (e: "dragLineEnd", value: LineData["lines"][number]): void;
}>();

const shape = ref<DC<Line>>();
const points = computed(() => [
  props.data.points.find((p) => p.id === props.line.a)!,
  props.data.points.find((p) => p.id === props.line.b)!,
]);
const lineData = computed(() => props.line);
const describes = mergeDescribes(lineData, {}, ["stroke", "strokeWidth"]);
const d = describes as any;
d.strokeWidth.props = {
  ...d.strokeWidth.props,
  proportion: true,
};
d.strokeWidth.label = "粗细";
d.stroke.label = "颜色";

let isStartChange = false;
let setLineVector: Vector2;
describes.length = {
  type: "inputNum",
  label: "线段长度",
  "layout-type": "row",
  get value() {
    return lineLen(points.value[0], points.value[1]);
  },
  set value(val) {
    if (!isStartChange) {
      emit("updateBefore", [props.line.a, props.line.b]);
      setLineVector = lineVector(points.value);
    }
    isStartChange = true;
    const aCount = props.data.lines.filter(
      (line) => line.a === points.value[0].id || line.b === points.value[0].id
    ).length;
    const bCount = props.data.lines.filter(
      (line) => line.a === points.value[1].id || line.b === points.value[1].id
    ).length;

    if (aCount === bCount || (aCount > 1 && bCount > 1)) {
      // 两端伸展
      const center = lineCenter(points.value);
      const l1 = getVectorLine(setLineVector.clone().multiplyScalar(-1), center, val / 2);
      const l2 = getVectorLine(setLineVector, center, val / 2);
      emit("updatePoint", { ...points.value[0], ...l1[1] });
      emit("updatePoint", { ...points.value[1], ...l2[1] });
    } else {
      // 单端伸展
      const changeNdx = aCount > 1 ? 1 : 0;
      const start = points.value[aCount > 1 ? 0 : 1];
      const lineVec =
        aCount > 1 ? setLineVector : setLineVector.clone().multiplyScalar(-1);
      const line = getVectorLine(lineVec, start, val);
      emit("updatePoint", { ...points.value[changeNdx], ...line[1] });
    }
  },
  props: { proportion: true },
};

const delHandler = () => {
  emit("updateBefore", [props.line.a, props.line.b]);
  emit("delLine");
  emit("update");
};
const menus = [
  {
    label: "删除",
    handler: delHandler,
  },
];

const status = useMouseShapeStatus(shape);
const [mstyle] = useAnimationMouseStyle({
  shape,
  getMouseStyle,
  data: lineData as any,
});
const isDrawIng = computed(
  () =>
    props.addMode && props.data.lines.indexOf(props.line) === props.data.lines.length - 1
);

const style = computed(() =>
  isDrawIng.value ? { ...mstyle.value, stroke: themeColor } : mstyle.value
);

const addPoint = (pos: Pos) => {
  emit("updateBefore", []);
  emit("addPoint", { ...points.value[0], ...pos, id: onlyId() });
  emit("update");
};

const config = useConfig();
const delPoint = (point: LineData["points"][number]) => {
  emit("updateBefore", []);
  emit("delPoint", point);
  emit("update");
};

const infos = useCustomSnapInfos();
let snapInfos: ComponentSnapInfo[];
const dragstartHandler = (eIds: string[]) => {
  emit("updateBefore", eIds);

  snapInfos = getSnapInfos({
    ...props.data,
    lines: props.data.lines.filter(
      (item) => !(eIds.includes(item.a) || eIds.includes(item.b))
    ),
    points: props.data.points.filter((item) => !eIds.includes(item.id)),
  });
  snapInfos.forEach((item) => {
    infos.add(item);
  });
};
const dragendHandler = () => {
  emit("update");
  snapInfos.forEach((item) => infos.remove(item));
};

// const padstart = computed(() => {
//   props.line.
// })
</script>
