<template>
  <v-group :config="matConfig" ref="shape">
    <v-rect
      name="repShape"
      :config="{
        x: -rang,
        y: -rang,
        width: data.width + 2 * rang,
        height: data.height + 2 * rang,
      }"
    >
    </v-rect>
    <v-line
      ref="line"
      :config="{
        points: getBorderPoints(),
        ...data,
        closed: true,
        zIndex: undefined,
      }"
    />
    <template v-for="(row, rowNdx) in data.content">
      <template v-for="(col, colNdx) in row">
        <ShareText
          :config="{
            ...defaultCollData,
            ...col,
            ...getBound(rowNdx, colNdx),
            text: col.content,
            fill: col.fontColor,
          }"
          :parent-id="data.id"
          :editer="editer && !col.readonly"
          @update-text="(val) => emit('updateContent', { rowNdx, colNdx, val })"
          @update:is-edit="(val) => emit('update:isEdit', { rowNdx, colNdx, val })"
        />
      </template>
    </template>
  </v-group>
</template>

<script lang="ts" setup>
import ShareText from "../share/text.vue";
import { defaultStyle, TableData, defaultCollData } from "./index.ts";
import { computed, ref } from "vue";
import { DC } from "@/deconstruction.js";
import { Transform } from "konva/lib/Util";
import { Group } from "konva/lib/Group";
import { useStage } from "@/core/hook/use-global-vars.ts";
import { Line } from "konva/lib/shapes/Line";
import { useViewerInvertTransform, useViewerTransform } from "@/core/hook/use-viewer.ts";
import { lineLen, Pos } from "@/utils/math.ts";

const props = defineProps<{ data: TableData; addMode?: boolean; editer?: boolean }>();
const data = computed(() => ({ ...defaultStyle, ...props.data }));
const emit = defineEmits<{
  (e: "updateContent", data: { rowNdx: number; colNdx: number; val: string }): void;
  (e: "update:isEdit", data: { rowNdx: number; colNdx: number; val: boolean }): void;
}>();

const shape = ref<DC<Group>>();
const line = ref<DC<Line>>();

const getBound = (rowNdx: number, colNdx: number) => {
  let x = 0,
    y = 0;
  for (let i = 0; i < rowNdx; i++) {
    y += data.value.content[i][0].height;
  }
  for (let i = 0; i < colNdx; i++) {
    x += data.value.content[rowNdx][i].width;
  }
  const { width, height } = data.value.content[rowNdx][colNdx];
  return { x, y, width, height };
};

const getBorderPoints = () => {
  const points: number[] = [];
  const rows = data.value.content;
  let ry = 0;
  let rx = 0;
  for (let i = 0; i < rows.length; i++) {
    const cols = rows[i];
    for (let j = 0; j < cols.length; j++) {
      const { x, y, width, height } = getBound(i, j);
      points.push(x, y, x + width, y, x + width, y + height, x, y + height, x, y);
      ry = y + height;
      rx = x;
    }
    points.push(rx, ry);
  }
  points.push(0, ry);
  return points;
};

const matConfig = computed(() => {
  const mat = new Transform(data.value.mat);
  return mat.decompose();
});

let rang = 5;
const stage = useStage();
const viewInverTransform = useViewerInvertTransform();
const viewTransform = useViewerTransform();
const getMouseIntersect = (pos?: Pos) => {
  const $line = line.value?.getNode();
  if (!pos) {
    const $stage = stage.value?.getStage();
    pos = $stage?.getPointerPosition() as any;
  }
  if (!pos || !$line) return null;
  if (!$line.intersects(pos)) return null;

  pos = viewInverTransform.value.point(pos);
  pos = new Transform(data.value.mat).invert().point(pos);

  const swPixel = lineLen(
    viewTransform.value.point({ x: data.value.strokeWidth, y: 0 }),
    viewTransform.value.point({ x: 0, y: 0 })
  );
  const check = Math.max(rang, swPixel);
  let rowBorderNdx = -1;
  let colBorderNdx = -1;
  let rowNdx = -1;
  let colNdx = -1;

  for (let i = 0; i < data.value.content.length; i++) {
    const rb = getBound(i, 0);
    rb.x += matConfig.value.x;
    rb.x += matConfig.value.y;
    const td = pos.y - rb.y;
    const bd = pos.y - rb.y - rb.height;

    if (td < -check || bd > check) {
      continue;
    }
    if (Math.abs(td) < check) {
      rowBorderNdx = i;
    }
    if (Math.abs(bd) < check) {
      rowBorderNdx = i + 1;
    }
    rowNdx = i;

    const row = data.value.content[i];
    let j = 0;
    for (; j < row.length; j++) {
      const cb = getBound(i, j);
      const ld = pos.x - cb.x;
      const rd = pos.x - cb.x - cb.width;

      if (ld < -check || rd > check) {
        continue;
      }
      if (Math.abs(ld) < check) {
        colBorderNdx = j;
      }
      if (Math.abs(rd) < check) {
        colBorderNdx = j + 1;
      }
      colNdx = j;
      break;
    }
    if (j !== row.length) {
      break;
    }
  }
  return { rowBorderNdx, colBorderNdx, rowNdx, colNdx };
};

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