<template>
  <v-circle
    :config="{ ...style, ...position, hitStrokeWidth: style.strokeWidth }"
    ref="circle"
  />
  <Operate :target="circle" :menus="[{ label: '删除', handler: () => emit('delete') }]" />
</template>

<script lang="ts" setup>
import { Pos } from "@/utils/math.ts";
import { themeColor } from "@/constant";
import { computed, ref, watch } from "vue";
import { DC } from "@/deconstruction";
import { Circle } from "konva/lib/shapes/Circle";
import { useShapeDrag } from "@/core/hook/use-transformer.ts";
import { getMouseColors } from "@/utils/colors";
import { useCustomSnapInfos, useGlobalSnapInfos, useSnap } from "@/core/hook/use-snap";
import { generateSnapInfos } from "../util";
import { ComponentSnapInfo } from "..";
import { useShapeIsHover } from "@/core/hook/use-mouse-status";
import { useCursor } from "@/core/hook/use-global-vars";
import { rangMod } from "@/utils/shared";
import { Operate } from "../../html-mount/propertys/index.ts";

const props = defineProps<{
  points: Pos[];
  ndx: number;
  id: string;
  color?: string;
  size?: number;
  disable?: boolean;
  opacity?: number;
  closed?: boolean;
  notDelete?: boolean;
  getSelfSnapInfos?: (point: Pos) => ComponentSnapInfo[];
}>();
const emit = defineEmits<{
  (e: "update:position", position: Pos): void;
  (e: "dragend"): void;
  (e: "dragstart"): void;
  (e: "delete"): void;
}>();

const position = computed(() => props.points[props.ndx]);

const style = computed(() => {
  const color = getMouseColors(props.color || themeColor);
  const size = props.size || 5;
  return {
    radius: size / 2,
    fill: isHover.value || dragIng.value ? "#fff" : color.pub,
    stroke: color.pub,
    strokeWidth: size / 4,
    opacity: props.opacity !== undefined ? props.opacity : props.disable ? 0.5 : 1,
  };
});

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

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

const snapInfos = useGlobalSnapInfos();
const refSnapInfos = computed(() => {
  if (!props.id) {
    return snapInfos.value;
  } else {
    return snapInfos.value.filter((p) => !("id" in p) || p.id !== props.id);
  }
});
const snap = useSnap(refSnapInfos);
const circle = ref<DC<Circle>>();
const offset = useShapeDrag(circle);
const hResult = useShapeIsHover(circle);
const isHover = hResult[0];
const cursor = useCursor();
if (!props.notDelete) {
  watch(
    isHover,
    (hover, _, onCleanup) => {
      if (hover) {
        onCleanup(cursor.push("/icons/m_move.png"));
      }
    },
    { immediate: true }
  );
}
const dragIng = ref(false);
let init: Pos;
watch(offset, (offset, oldOffsert) => {
  snap.clear();
  if (!oldOffsert) {
    init = { ...position.value };
    startHandler();
    emit("dragstart");
    cursor.push("/icons/m_move.png");
    dragIng.value = true;
  }
  if (offset) {
    const point = {
      x: init.x + offset.x,
      y: init.y + offset.y,
    };
    const refSnapInfos = props.getSelfSnapInfos
      ? props.getSelfSnapInfos(point)
      : generateSnapInfos([point], true, true);
    // console.log(refSnapInfos);
    const transform = snap.move(refSnapInfos);
    emit("update:position", transform ? transform.point(point) : point);
  } else {
    emit("dragend");
    cursor.pop();
    clearInfos();
    dragIng.value = false;
  }
});

watch(
  () => props.disable,
  (disable) => {
    if (disable) {
      offset.pause();
      hResult.pause();
    } else {
      offset.resume();
      hResult.resume();
    }
  },
  { immediate: true }
);

defineExpose({
  get shape() {
    return circle.value;
  },
});
</script>
