<template>
  <v-group ref="shape">
    <v-line
      name="repShape"
      :config="{
        ...data,
        zIndex: undefined,
        points: flatPositions(data.points),
        opacity: addMode ? 0.3 : data.opacity,
        hitFunc,
      }"
    >
    </v-line>
    <Point
      v-for="(p, ndx) in data.points"
      :id="data.id + ndx"
      :shapeId="data.id"
      :position="p"
      :size="data.strokeWidth + 6"
      :color="data.stroke"
      @update:position="(p) => emit('update:position', { ndx, val: p })"
      @dragend="endHandler()"
      @dragstart="startHandler(ndx)"
    />
  </v-group>
</template>

<script lang="ts" setup>
import Point from "../share/point.vue";
import { defaultStyle, LineData } from "./index.ts";
import { flatPositions } from "@/utils/shared.ts";
import { computed, ref } from "vue";
import { DC } from "@/deconstruction.js";
import { Line, LineConfig } from "konva/lib/shapes/Line";
import { Pos } from "@/utils/math.ts";
import { useCustomSnapInfos } from "@/core/hook/use-snap.ts";
import { generateSnapInfos } from "../util.ts";
import { ComponentSnapInfo } from "../index.ts";

const props = defineProps<{
  data: LineData;
  addMode?: boolean;
  canEdit?: boolean;
  shapeId?: string;
}>();
const emit = defineEmits<{
  (e: "update:position", data: { ndx: number; val: Pos }): void;
  (e: "update"): void;
}>();

const data = computed(() => ({ ...defaultStyle, ...props.data }));

const hitFunc: LineConfig["hitFunc"] = (con, shape) => {
  con.beginPath();
  con.moveTo(data.value.points[0].x, data.value.points[0].y);
  for (let i = 1; i < data.value.points.length; i++) {
    con.lineTo(data.value.points[i].x, data.value.points[i].y);
  }
  con.closePath();
  con.fillStrokeShape(shape);
};

const infos = useCustomSnapInfos();
const addedInfos = [] as ComponentSnapInfo[];
const clearInfos = () => {
  addedInfos.forEach(infos.remove);
};

const startHandler = (ndx: number) => {
  clearInfos();
  const geos = [
    props.data.points.slice(0, ndx),
    props.data.points.slice(ndx + 1, props.data.points.length),
  ];
  if (ndx > 0 && ndx < props.data.points.length - 1) {
    geos.push([props.data.points[ndx - 1], props.data.points[ndx + 1]]);
  }
  geos.forEach((geo) => {
    const snapInfos = generateSnapInfos(geo, true, true, true);
    snapInfos.forEach((item) => {
      infos.add(item);
      addedInfos.push(item);
    });
  });
};

const endHandler = () => {
  clearInfos();
  emit("update");
};

const shape = ref<DC<Line>>();
defineExpose({
  get shape() {
    return shape.value;
  },
});
</script>
