<script lang="ts" setup>
import type { CSSProperties } from 'vue';
import { computed, defineModel, ref, useSlots, watch, watchEffect } from 'vue';
import { useDraggable } from '@vueuse/core';
import type { UModalProps } from './types';

const props = withDefaults(defineProps<UModalProps>(), {
  draggable: true,
  closable: true,
  keyboard: true,
  mask: true,
  zIndex: 1000,
  maskClosable: true,
  getContainer: () => document.body
});

const slots = useSlots();
defineOptions({
  inheritAttrs: false
});

const open = defineModel<boolean>('open', { required: false, default: false });
/**
 * 处理拖拽
 */
const modalTitleRef = ref();
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();
    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)`,
  };
});
</script>

<template>
  <a-modal
    v-bind="props"
    v-model:open="open"
    class="u-modal"
    :class="props.class"
    :title="undefined"
  >
    <template #title>
      <slot v-if="draggable" name="title">
        <div ref="modalTitleRef" style="width: 100%; cursor: move">
          {{ title }}
        </div>
      </slot>
      <slot v-else name="title">
        {{ title }}
      </slot>
    </template>
    <template #modalRender="{ originVNode }">
      <div :style="transformStyle">
        <component :is="originVNode" />
      </div>
    </template>
    <template v-for="(slot, name) in slots" :key="name" #[name]="slotProps">
      <slot :key="name" :name="name" v-bind="slotProps" />
    </template>
  </a-modal>
</template>

<style lang="scss" scoped></style>
