<template>
  <Modal
    v-model:open="show"
    :width="width"
    :wrap-style="{ overflow: 'hidden' }"
    :destroyOnClose="true"
    :maskClosable="false"
  >
    <template #title>
      <div ref="modalTitleRef" style="width: 100%; cursor: move">{{ title }}</div>
    </template>
    <template #modalRender="{ originVNode }">
      <div :style="transformStyle">
        <component :is="originVNode" />
      </div>
    </template>
    <Editor v-model:code="code" v-bind="$attrs" :language="language"/>
    <template #footer>
      <slot name="footer">
        <Button @click="close">取消</Button>
        <Button type="primary" @click="handleOk">确定</Button>
      </slot>
    </template>
  </Modal>
</template>

<script lang="ts">
import { Modal, Button } from "ant-design-vue";
import { ref, defineComponent, watch, watchEffect, computed, CSSProperties } from "vue";
import Editor, { Language } from "./Editor.vue";
import { useDraggable } from '@vueuse/core';

export default defineComponent({
  name: "DEditorModal",
  components: {
    Modal,
    Editor,
    Button
  },
  props: {
    title: {
      type: String,
      default: "编辑",
    },
    width: {
      type: Number,
      default: 800,
    },
  },
  emits: ["ok"],
  setup(_, { emit }) {
    const show = ref(false);
    const code = ref("");
    const language = ref<Language>();
    const modalTitleRef = ref<HTMLElement>();

    const { x, y, isDragging } = useDraggable(modalTitleRef);
    const startX = ref<number>(0);
    const startY = ref<number>(0);
    const startedDrag = ref(false);
    const transformX = ref(0);
    const transformY = ref(0);
    const preTransformX = ref(0);
    const preTransformY = ref(0);
    const dragRect = ref({ left: 0, right: 0, top: 0, bottom: 0 });
    watch([x, y], () => {
      if (!startedDrag.value) {
        startX.value = x.value;
        startY.value = y.value;
        const bodyRect = document.body.getBoundingClientRect();
        const titleRect = modalTitleRef.value?.getBoundingClientRect() || { width: 0, height: 0 };
        dragRect.value.right = bodyRect.width - titleRect.width;
        dragRect.value.bottom = bodyRect.height - titleRect.height;
        preTransformX.value = transformX.value;
        preTransformY.value = transformY.value;
      }
      startedDrag.value = true;
    });
    watch(isDragging, () => {
      if (!isDragging) {
        startedDrag.value = false;
      }
    });

    watchEffect(() => {
      if (startedDrag.value) {
        transformX.value =
          preTransformX.value +
          Math.min(Math.max(dragRect.value.left, x.value), dragRect.value.right) -
          startX.value;
        transformY.value =
          preTransformY.value +
          Math.min(Math.max(dragRect.value.top, y.value), dragRect.value.bottom) -
          startY.value;
      }
    });
    const transformStyle = computed<CSSProperties>(() => {
      return {
        transform: `translate(${transformX.value}px, ${transformY.value}px)`,
      };
    });
    const handleOk = () => {
      // TODO: 检验code
      emit("ok", code.value);
      show.value = false;
    };

    const open = (codeStr: string, lang: Language = 'javascript') => {
      show.value = true;
      code.value = codeStr;
      language.value = lang;
    };
    const close = () => {
      show.value = false;
    };

    return {
      open,
      close,
      code,
      handleOk,
      show,
      language,
      modalTitleRef,
      transformStyle
    };
  },
});
</script>

<style scoped></style>
