<template>
  <template v-if="axissInfo">
    <v-group v-for="info in axissInfo" :config="{ listening: false }">
      <v-line :config="{ points: info.points, ...style }" />
      <v-text
        :config="{ ...style, strokeWidth: 0, ...textConfig, fontSize, align: 'center' }"
        v-for="textConfig in info.texts"
      />
    </v-group>
  </template>
</template>

<script lang="ts" setup>
import { computed, onUnmounted } from "vue";
import { components } from "../components";
import { useComponentsAttach } from "../hook/use-component";
import { useViewerTransform } from "../hook/use-viewer";
import { useResize } from "../hook/use-event";
import { Pos } from "@/utils/math";
import { TextConfig } from "konva/lib/shapes/Text";
import { Transform } from "konva/lib/Util";

const style = {
  stroke: "#000",
  strokeWidth: 1,
  opacity: 1,
  strokeScaleEnabled: false,
  shadowColor: "#fff",
  shadowBlur: 3,
  shadowOffset: { x: 0, y: 0 },
  shadowOpacity: 1,
};

const props = withDefaults(
  defineProps<{
    splitOffset?: number;
    showOffset?: number;
    splitWidth?: number;
  }>(),
  { splitOffset: 80, showOffset: 20, splitWidth: 10 }
);

const size = useResize();
const center = computed(() => {
  if (!size.value) return;
  return {
    x: size.value.width / 2,
    y: size.value.height / 2,
  };
});
const rang = computed(() => {
  if (!size.value) return;
  return {
    lt: { x: props.showOffset, y: props.showOffset },
    rb: {
      x: size.value.width - props.showOffset,
      y: size.value.height - props.showOffset,
    },
  };
});

const compsInfo = useComponentsAttach(
  (type, item) => components[type].getSnapPoints(item as any)
  // ["polygon"]
);
onUnmounted(compsInfo.cleanup);

const viewerTransform = useViewerTransform();
const points = computed(() => compsInfo.attachs.flatMap((p) => p));
const rectAxisSteps = computed(() => {
  const axis = {
    top: [] as number[],
    left: [] as number[],
    right: [] as number[],
    bottom: [] as number[],
  };
  if (!center.value || !rang.value) return axis;

  const pushStep = (axis: number[], cur: number, pixel: Pos) => {
    if (
      !(
        pixel.x >= rang.value!.lt.x &&
        pixel.x <= rang.value!.rb.x &&
        pixel.y >= rang.value!.lt.y &&
        pixel.y <= rang.value!.rb.y
      )
    ) {
      return;
    }

    const can = (data: number) => Math.abs(data - cur) > props.splitOffset;

    let i = axis.length - 1;
    for (i; i >= 0; i--) {
      if (axis[i] < cur) {
        break;
      }
    }

    if (axis.length === 0) {
      axis.push(cur);
    } else if (can(axis[i]) && (i === axis.length - 1 || can(axis[i + 1]))) {
      axis.splice(i + 1, 0, cur);
    } else if (i === -1) {
      axis[0] = cur;
    } else if (i === axis.length - 1) {
      axis[i] = cur;
    }
  };

  for (const point of points.value) {
    const pixel = viewerTransform.value.point(point);
    pushStep(pixel.x > center.value.x ? axis.right : axis.left, pixel.y, pixel);
    pushStep(pixel.y > center.value.y ? axis.bottom : axis.top, pixel.x, pixel);
  }
  return axis;
});

const fontSize = 12;
const axissInfo = computed(() => {
  if (!rang.value) return;
  const infos: Record<string, { points: number[]; texts: TextConfig[] }> = {
    left: { points: [], texts: [] },
    right: { points: [], texts: [] },
    top: { points: [], texts: [] },
    bottom: { points: [], texts: [] },
  };

  if (rectAxisSteps.value.left.length > 1) {
    for (let i = 0; i < rectAxisSteps.value.left.length; i++) {
      const cur = rectAxisSteps.value.left[i];
      infos.left.points.push(rang.value!.lt.x, cur);
      infos.left.points.push(rang.value!.lt.x + props.splitWidth, cur);
      infos.left.points.push(rang.value!.lt.x, cur);

      if (i === 0) continue;
      const prev = rectAxisSteps.value.left[i - 1];
      const lt = {
        x: rang.value!.lt.x + fontSize / 2,
        y: prev,
      };
      const width = cur - prev;
      const height = fontSize;
      const center = { x: 0, y: height / 2 };

      const tf = new Transform()
        .translate(center.x + lt.x, center.y + lt.y)
        .rotate(Math.PI / 2)
        .translate(-center.x, -center.y);

      infos.left.texts.push({
        width: width,
        text: Math.floor(width * 100).toString(),
        ...tf.decompose(),
      });
    }
  }

  if (rectAxisSteps.value.right.length > 1) {
    for (let i = 0; i < rectAxisSteps.value.right.length; i++) {
      const cur = rectAxisSteps.value.right[i];
      infos.right.points.push(rang.value!.rb.x, cur);
      infos.right.points.push(rang.value!.rb.x - props.splitWidth, cur);
      infos.right.points.push(rang.value!.rb.x, cur);

      if (i === 0) continue;
      const prev = rectAxisSteps.value.right[i - 1];
      const lt = {
        x: rang.value!.rb.x - fontSize / 1.5,
        y: prev,
      };
      const width = cur - prev;
      const height = fontSize;
      const center = { x: 0, y: height / 2 };

      const tf = new Transform()
        .translate(center.x + lt.x, center.y + lt.y)
        .rotate(Math.PI / 2)
        .translate(-center.x, -center.y);

      infos.right.texts.push({
        width: width,
        text: Math.floor(width * 100).toString(),
        ...tf.decompose(),
      });
    }
  }

  if (rectAxisSteps.value.top.length > 1) {
    for (let i = 0; i < rectAxisSteps.value.top.length; i++) {
      const cur = rectAxisSteps.value.top[i];
      infos.top.points.push(cur, rang.value!.lt.y);
      infos.top.points.push(cur, rang.value!.lt.y + props.splitWidth);
      infos.top.points.push(cur, rang.value!.lt.y);

      if (i === 0) continue;
      const prev = rectAxisSteps.value.top[i - 1];
      const lt = {
        x: prev,
        y: rang.value!.lt.y + fontSize / 3,
      };

      const width = cur - prev;
      infos.top.texts.push({
        width: width,
        text: Math.floor(width * 100).toString(),
        ...lt,
      });
    }
  }

  if (rectAxisSteps.value.bottom.length > 1) {
    for (let i = 0; i < rectAxisSteps.value.bottom.length; i++) {
      const cur = rectAxisSteps.value.bottom[i];
      infos.bottom.points.push(cur, rang.value!.rb.y);
      infos.bottom.points.push(cur, rang.value!.rb.y - props.splitWidth);
      infos.bottom.points.push(cur, rang.value!.rb.y);

      if (i === 0) continue;
      const prev = rectAxisSteps.value.bottom[i - 1];
      const lt = {
        x: prev,
        y: rang.value!.rb.y - fontSize,
      };

      const width = cur - prev;
      infos.bottom.texts.push({
        width: width,
        text: Math.floor(width * 100).toString(),
        ...lt,
      });
    }
  }

  return infos;
});
</script>
