<template>
  <a-modal
    ref="modalRef"
    :wrap-style="{ overflow: 'hidden' }"
    @ok="handleOk"
    @cancel="close"
    :closable="false"
    v-bind="{
      cancelText: '取消',
      okText: '确定',
      ...props
    }"
    :confirmLoading="state.confirmLoading"
  >
    <template #title>
      <div ref="modalTitleRef" style="width: 100%; cursor: move">{{props.label || 'model'}}</div>
    </template>
    <template #modalRender="{ originVNode }">
      <div :style="transformStyle">
        <component :is="originVNode" />
      </div>
    </template>
    <slot></slot>
  </a-modal>
</template>

<script lang="ts" setup >
import { useDraggable } from '@vueuse/core'
import { ModalProps } from 'ant-design-vue'
import { ref, watch, watchEffect, computed, CSSProperties, reactive, onMounted } from 'vue'

export interface ModalProPorps extends ModalProps {
  label: string,
  openConfirmLoading?: boolean,
  cancel?: () => void
}

export interface ModalOkProps {
  confirmed: () => void
  confirmStart: () => void
}

const emit = defineEmits<{
  (e: 'close'): void
  (e: 'ok', { confirmStart, confirmed }: ModalOkProps): void
}>()

const props = defineProps<ModalProPorps>()

interface StateProps {
  confirmLoading: boolean
}

const state = reactive<Partial<StateProps>>({})

const close = () => emit('close')

const handleOk = async () => {
  emit('ok', {
    confirmStart: () => state.confirmLoading = true,
    confirmed: () => state.confirmLoading = 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>

<style>

</style>
