<template>
  <TempText
    :data="tData"
    editer
    @update-content="submitHandler"
    :ref="(v: any) => shape = v?.shape"
  />
  <PropertyUpdate
    :describes="describes"
    :data="data"
    :target="shape"
    @change="emit('updateShape', { ...data })"
  />
  <Operate :target="shape" :menus="operateMenus" />
</template>

<script lang="ts" setup>
import { TextData, getMouseStyle, defaultStyle } from "./index.ts";
import { PropertyUpdate, Operate } from "../../propertys";
import TempText from "./temp-text.vue";
import { useComponentStatus } from "@/core/hook/use-component.ts";
import { cloneRepShape, useCustomTransformer } from "@/core/hook/use-transformer.ts";
import { Transform } from "konva/lib/Util";
import { Text } from "konva/lib/shapes/Text";
import { computed, ref, watch } from "vue";
import { setShapeTransform } from "@/utils/shape.ts";
import { zeroEq } from "@/utils/math.ts";
import { MathUtils } from "three";

const props = defineProps<{ data: TextData }>();
const emit = defineEmits<{
  (e: "updateShape", value: TextData): void;
  (e: "addShape", value: TextData): void;
  (e: "delShape"): void;
}>();

const { shape, tData, data, operateMenus, describes } = useComponentStatus<
  Text,
  TextData
>({
  emit,
  props,
  getMouseStyle,
  defaultStyle,
  transformType: "custom",
  customTransform(callback, shape, data) {
    useCustomTransformer(shape, data, {
      openSnap: true,
      getRepShape($shape) {
        const repShape = cloneRepShape($shape).shape;
        return {
          shape: repShape,
          update(data) {
            data.width && repShape.width(data.width);
            data.fontSize && repShape.fontSize(data.fontSize);
            setShapeTransform(repShape, new Transform(data.mat));
          },
        };
      },
      transformerConfig: {
        rotateEnabled: true,
        enabledAnchors: ["middle-left", "middle-right"],
        boundBoxFunc: (oldBox, newBox) => {
          if (newBox.width - minWidth.value < -0.01) {
            return oldBox;
          }
          return newBox;
        },
      },
      beforeHandler(data, mat) {
        return { ...data, ...update(mat, data) };
      },
      handler(data, mat) {
        const setAttrib = update(mat, data);
        Object.assign(data, setAttrib);
        if (setAttrib.width) {
          return true;
        }
      },
      callback,
    });
  },
  copyHandler(tf, data) {
    return {
      ...data,
      mat: tf.multiply(new Transform(data.mat)).m,
    };
  },
  propertys: [
    "fill",
    "stroke",
    "strokeWidth",
    "dash",
    "opacity",
    "fontSize",
    "align",
    "fontStyle",
    // "ref",
    // "zIndex",
  ],
});

const minWidth = computed(() => (data.value.fontSize || 12) * 2);
const getWidth = (data: TextData, scaleX: number) => {
  let width: number;
  if ("width" in data) {
    width = Math.max(data.width! * scaleX, minWidth.value);
  } else {
    width = Math.max(shape.value!.getNode()!.width() * scaleX, minWidth.value);
  }
  return width;
};

const update = (mat: Transform, data: TextData) => {
  const { scaleX, x, y, rotation } = mat.decompose();
  if (!zeroEq(scaleX - 1)) {
    return {
      width: getWidth(data, scaleX),
      mat: new Transform()
        .translate(x, y)
        .rotate(MathUtils.degToRad(rotation))
        .scale(1, 1).m,
    };
  } else {
    return {
      mat: mat.m,
    };
  }
};

// 字体大小变化时，更新width
watch(
  () => data.value.fontSize,
  () => {
    data.value.width = getWidth(data.value, 1);
    const $shape = shape.value?.getNode();
    $shape && $shape.fire("bound-change");
  }
);

const submitHandler = (val: string) => {
  if (val !== data.value.content) {
    data.value.content = val;
    emit("updateShape", { ...data.value });
  }
};
</script>
