<template>
  <a-modal
    v-model:open="visible"
    width="100%"
    :footer="false"
    :closable="false"
    :maskClosable="false"
    wrapClassName="cut-image-dialog full-modal"
  >
    <div ref="imgContainRef" class="cut-image">
      <div v-if="visible" class="cut-image-body" :style="imageStyle">
        <img ref="imgRef" :src="sheetUrl" alt="原图" @load="initImageSize" />

        <element-resize
          v-if="selection.w"
          v-model="selection"
          class="element-resize-act"
          :active="['r', 'rb', 'b', 'lb', 'l', 'lt', 't', 'rt']"
        >
          <div class="image-selection" :style="selectionStyle"></div>
        </element-resize>
      </div>

      <div class="cut-image-action">
        <div class="cut-close" @click="close"><CloseOutlined /></div>
        <div class="cut-save" @click="confirm"><SaveOutlined /></div>
      </div>
    </div>
  </a-modal>
</template>

<script setup lang="ts">
import { computed, ref, watch } from "vue";
import { SaveOutlined, CloseOutlined } from "@ant-design/icons-vue";
import useModal from "@/hooks/useModal";
import { objAssign } from "@/utils/tool";

import ElementResize from "@/components/ElementResize/index.vue";

defineOptions({
  name: "CutImageDialog",
});

/* modal */
const { visible, open, close } = useModal();
defineExpose({ open, close });

const props = defineProps<{
  sheetUrl: string;
  sliceSelection?: AreaSize;
}>();

const emit = defineEmits(["confirm"]);

const initSelection = {
  w: 0,
  h: 0,
  x: 0,
  y: 0,
};

const originImgRef = ref();
const curCroppper = ref();
const showCanvas = ref(false);
const selection = ref({
  ...initSelection,
});

const selectionStyle = computed(() => {
  return {
    width: `${selection.value.w}px`,
    height: `${selection.value.h}px`,
    top: `${selection.value.y}px`,
    left: `${selection.value.x}px`,
  };
});

const imageSize = ref({
  width: 0,
  height: 0,
  left: 0,
  top: 0,
});
const imageStyle = computed(() => {
  return {
    width: `${imageSize.value.width}px`,
    height: `${imageSize.value.height}px`,
    top: `${imageSize.value.top}px`,
    left: `${imageSize.value.left}px`,
  };
});

const imgContainRef = ref();
const imgRef = ref();

function initImageSize() {
  const imgDom = imgRef.value as HTMLImageElement;
  const elDom = imgContainRef.value as HTMLDivElement;

  const imgSize = getImageSizePos({
    win: {
      width: elDom.clientWidth,
      height: elDom.clientHeight,
    },
    img: {
      width: imgDom.naturalWidth,
      height: imgDom.naturalHeight,
    },
    rotate: 0,
  });
  imageSize.value = objAssign(imageSize.value, imgSize);

  if (!props.sliceSelection) return;
  const rate = imgDom.naturalWidth / imageSize.value.width;
  selection.value = {
    x: props.sliceSelection.x / rate,
    y: props.sliceSelection.y / rate,
    w: props.sliceSelection.w / rate,
    h: props.sliceSelection.h / rate,
  };
}

interface AreaSize {
  width: number;
  height: number;
}
function getImageSizePos({
  win,
  img,
  rotate,
}: {
  win: AreaSize;
  img: AreaSize;
  rotate: number;
}) {
  const imageSize = {
    width: 0,
    height: 0,
    top: 0,
    left: 0,
  };
  const isHorizontal = !!(rotate % 180);

  const rateWin = isHorizontal
    ? win.height / win.width
    : win.width / win.height;
  const hwin = isHorizontal
    ? {
        width: win.height,
        height: win.width,
      }
    : win;

  const rateImg = img.width / img.height;

  if (rateImg <= rateWin) {
    imageSize.height = Math.min(hwin.height, img.height);
    imageSize.width = Math.floor((imageSize.height * img.width) / img.height);
  } else {
    imageSize.width = Math.min(hwin.width, img.width);
    imageSize.height = Math.floor((imageSize.width * img.height) / img.width);
  }
  imageSize.left = (win.width - imageSize.width) / 2;
  imageSize.top = (win.height - imageSize.height) / 2;
  return imageSize;
}

async function confirm() {
  const imgDom = imgRef.value as HTMLImageElement;
  const rate = imageSize.value.width / imgDom.naturalWidth;

  const selectionArea: AreaSize = {
    x: selection.value.x / rate,
    y: selection.value.y / rate,
    w: selection.value.w / rate,
    h: selection.value.h / rate,
  };

  const file = await getSliceImage(imgDom, selectionArea).catch((e) => {
    console.error(e);
  });
  if (!file) return;
  console.log(file);
  emit("confirm", file);
  close();
}

function getSliceImage(
  imgDom: HTMLImageElement,
  area: AreaSize
): Promise<File> {
  return new Promise((resolve, reject) => {
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");
    if (!ctx) return reject(new Error("不支持canvas"));

    canvas.width = area.w;
    canvas.height = area.h;

    ctx.drawImage(
      imgDom,
      area.x,
      area.y,
      area.w,
      area.h,
      0,
      0,
      canvas.width,
      canvas.height
    );

    canvas.toBlob((blob) => {
      if (blob) {
        resolve(new File([blob], "slice.png", { type: "image/png" }));
      } else {
        reject(new Error("构建文件失败"));
      }
    });
  });
}

// init
watch(
  () => visible.value,
  (val) => {
    if (!val) {
      selection.value = {
        ...initSelection,
      };
    }
  },
  {
    immediate: true,
  }
);
</script>
