<template>
  <v-group ref="grid" v-if="hLines && rect" :config="{ listening: false }">
    <template v-for="item in hLines">
      <v-line
        v-for="l in item.children"
        :config="{
          points: [rect[0].x, l, rect[1].x, l],
          ...style,
          strokeWidth: style.strokeWidth * 0.33,
        }"
      />
    </template>
    <template v-for="item in vLines">
      <v-line
        v-for="l in item.children"
        :config="{
          points: [l, rect[0].y, l, rect[1].y],
          ...style,
          strokeWidth: style.strokeWidth * 0.33,
        }"
      />
    </template>

    <v-line
      v-for="item in hLines"
      :config="{ points: [rect[0].x, item.dividing, rect[1].x, item.dividing], ...style }"
    />
    <v-line
      v-for="item in vLines"
      :config="{ points: [item.dividing, rect[0].y, item.dividing, rect[1].y], ...style }"
    />
  </v-group>
</template>
<script lang="ts" setup>
import { computed, ref, watch } from "vue";
import { useResize } from "../hook/use-event";
import { useShapeStaticZindex } from "../hook/use-layer";
import {
  useViewerInvertTransform,
  useViewerTransform,
  useViewerTransformConfig,
} from "../hook/use-viewer";
import { DC } from "@/deconstruction";
import { Rect } from "konva/lib/shapes/Rect";
import { lineLen } from "@/utils/math";
import { debounce } from "@/utils/shared";

const grid = ref<DC<Rect>>();
useShapeStaticZindex(grid);

const style = {
  stroke: "#ccc",
  strokeWidth: 3,
  opacity: 0.4,
  strokeScaleEnabled: false,
};

const pixelSize = useResize();
const viewerInvertTransform = useViewerInvertTransform();
// 真实rect
const rect = computed(() => {
  if (!pixelSize.value) return null;
  const start = viewerInvertTransform.value.point({ x: 0, y: 0 });
  const end = viewerInvertTransform.value.point({
    x: pixelSize.value.width,
    y: pixelSize.value.height,
  });
  return [start, end];
});

// 看大格子的像素，100倍数
const offsetUnit = 100;
const minScalePixel = offsetUnit / 2;
const viewerTransform = useViewerTransform();
const viewerTransformConfig = useViewerTransformConfig();
const offset = ref(offsetUnit);
watch(
  () => `${viewerTransformConfig.value.scaleX},${viewerTransformConfig.value.scaleY}`,
  () => {
    offset.value = offsetUnit;
    const start = viewerTransform.value.point({ x: 0, y: 0 });
    let i = 0;
    while (true) {
      const end = viewerTransform.value.point({ x: offset.value, y: 0 });
      if (lineLen(start, end) >= minScalePixel) {
        break;
      }
      offset.value *= 2;
      i++;
      if (i > 200) {
        break;
      }
    }
  }
);

const getFinal = (val: number, isTop: boolean) => {
  let t = val / offset.value;
  t = isTop ? Math.floor(t) : Math.ceil(t);
  return offset.value * t;
};

type DireLine = {
  dividing: number;
  children: number[];
};

const getLines = (min: number, max: number) => {
  const isReverse = min > max;
  const start = getFinal(min, !isReverse);
  const end = getFinal(max, isReverse);
  const diff = isReverse ? -offset.value : offset.value;

  let current = start;
  const lines: DireLine[] = [];
  while (diff > 0 ? current <= end : current >= end) {
    const item: DireLine = {
      dividing: current,
      children: [],
    };

    const cOffset = ((diff > 0 ? -1 : 1) * offset.value) / 5;
    for (let i = 1; i < 5; i++) {
      item.children.push(current + cOffset * i);
    }
    lines.push(item);
    current += diff;
  }
  return lines;
};

const hLines = ref<DireLine[]>([]);
const vLines = ref<DireLine[]>([]);
watch(
  rect,
  debounce(() => {
    if (!rect.value) {
      hLines.value = [];
      vLines.value = [];
    } else {
      hLines.value = getLines(rect.value[0].y, rect.value[1].y);
      vLines.value = getLines(rect.value[0].x, rect.value[1].x);
    }
  }, 16),
  { immediate: true }
);
</script>
