<template>
  <Teleport to="body">
    <Transition name="confirm" @after-leave="emit('afterLeave')">
      <div v-if="visible" class="fixed inset-0 z-3000 flex items-center justify-center p-4">
        <!-- Backdrop -->
        <div class="confirm-backdrop absolute inset-0 bg-black/20" />

        <!-- Card -->
        <div
          class="confirm-card relative bg-white rounded-2xl max-w-full"
          :style="{ width: normalizedWidth }"
        >
          <!-- 右上角关闭按钮 -->
          <div class="absolute top-2 right-2 cursor-pointer" @click.stop="close">
            <el-icon><Close /></el-icon>
          </div>
          <div class="px-6 py-5">
            <!-- Icon -->
            <div
              class="mx-auto mb-3 flex h-10 w-10 items-center justify-center rounded-xl"
              :class="
                type === 'danger'
                  ? 'bg-red-50'
                  : type === 'warning'
                    ? 'bg-yellow-50'
                    : 'bg-indigo-50/80'
              "
            >
              <svg
                class="w-5 h-5"
                :class="
                  type === 'danger'
                    ? 'text-red-500'
                    : type === 'warning'
                      ? 'text-yellow-500'
                      : 'text-[#7083FF]'
                "
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="2"
                stroke-linecap="round"
                stroke-linejoin="round"
              >
                <circle cx="12" cy="12" r="10" />
                <line x1="12" y1="8" x2="12" y2="12" />
                <line x1="12" y1="16" x2="12.01" y2="16" />
              </svg>
            </div>

            <!-- Title -->
            <h3 class="text-center text-base font-600 text-gray-800 leading-6">
              {{ title }}
            </h3>

            <!-- Message -->
            <p v-if="message" class="mt-1.5 text-center text-13px text-gray-400 leading-5">
              <component :is="normalizedMessage" />
            </p>

            <!-- Actions -->
            <div class="mt-5 grid grid-cols-2 gap-2.5">
              <button
                v-if="showCancelButton"
                type="button"
                class="confirm-btn cancel-btn"
                @click.stop="onCancel"
              >
                {{ cancelText }}
              </button>
              <button
                v-if="showConfirmButton"
                type="button"
                class="confirm-btn primary-btn"
                :class="{ 'danger-btn': type === 'danger', 'warning-btn': type === 'warning' }"
                :disabled="loading"
                @click.stop="onConfirm"
              >
                <svg
                  v-if="loading"
                  class="animate-spin h-3.5 w-3.5 mr-1.5 text-white/70"
                  viewBox="0 0 24 24"
                  fill="none"
                >
                  <circle
                    cx="12"
                    cy="12"
                    r="10"
                    stroke="currentColor"
                    stroke-width="3"
                    class="opacity-25"
                  />
                  <path
                    fill="currentColor"
                    class="opacity-75"
                    d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
                  />
                </svg>
                {{ confirmText }}
              </button>
            </div>
          </div>
        </div>
      </div>
    </Transition>
  </Teleport>
</template>

<script setup lang="ts">
import type { MessageBoxProps } from './types'
import { Close } from '@element-plus/icons-vue'
const {
  title = '确认操作',
  message = '',
  confirmText = '确认',
  cancelText = '取消',
  width = 380,
  loading = false,
  type = 'primary',
  showCancelButton = true,
  showConfirmButton = true,
  validate = null,
  mousePosition,
} = defineProps<MessageBoxProps>()

const normalizedWidth = computed(() => (typeof width === 'number' ? `${width}px` : width))

const visible = defineModel<boolean>({ default: false })

const normalizedMousePosition = computed(() => {
  return {
    x: mousePosition.x + 'px',
    y: mousePosition.y + 'px',
  }
})

onMounted(() => {
  console.log('onMounted')
})
onUpdated(() => {
  console.log('onUpdated')
})
onUnmounted(() => {
  console.log('onUnmounted')
})

const normalizedMessage = computed(() => {
  if (!message) return ''

  if (typeof message === 'function') {
    return message
  } else {
    return () => message
  }
})

const emit = defineEmits<{
  confirm: [res: string | number | undefined]
  cancel: []
  close: []
  afterLeave: []
}>()

const close = () => {
  visible.value = false
  emit('close')
}

const onCancel = () => {
  emit('cancel')
  close()
}

const onConfirm = async () => {
  if (validate) {
    const res = await validate?.()
    emit('confirm', res as string | number)
    close()
  } else {
    emit('confirm', undefined)

    if (!loading) close()
  }
}

const open = () => {
  visible.value = true
}

defineExpose({ open, close })
</script>

<style scoped>
/* 背景透明度过渡：打开时 0→1，关闭时 1→0 */
.confirm-enter-active,
.confirm-leave-active {
  transition: opacity 0.2s ease;
}

.confirm-enter-from {
  opacity: 0;
}

.confirm-leave-to {
  opacity: 0;
}

/* card 动画 */

.confirm-enter-active .confirm-card {
  transition:
    transform 0.2s cubic-bezier(0.22, 1.2, 0.36, 1),
    opacity 0.2s ease;
}

.confirm-leave-active .confirm-card {
  transition:
    transform 0.2s ease,
    opacity 0.2s ease;
}

/* 从点击点展开（先用固定坐标 200px,200px 测试动画是否生效） */

.confirm-enter-from .confirm-card {
  /* transform: translate(calc(200px - 50vw), calc(200px - 50vh)) scale(0.1); */
  transform: translate(
      calc(v-bind('normalizedMousePosition.x') - 50vw),
      calc(v-bind('normalizedMousePosition.y') - 50vh)
    )
    scale(0.1);
  opacity: 0;
}

.confirm-enter-to .confirm-card {
  transform: translate(0, 0) scale(1);
  opacity: 1;
}

/* 关闭时缩回点击点 */

.confirm-leave-from .confirm-card {
  transform: translate(0, 0) scale(1);
  opacity: 1;
}

.confirm-leave-to .confirm-card {
  transform: translate(
      calc(v-bind('normalizedMousePosition.x') - 50vw),
      calc(v-bind('normalizedMousePosition.y') - 50vh)
    )
    scale(0.1);
  opacity: 0;
}

.confirm-card {
  box-shadow:
    0 8px 30px rgba(100, 116, 180, 0.16),
    0 2px 6px rgba(0, 0, 0, 0.04);
}

.confirm-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 36px;
  border-radius: 10px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s ease;
  border: none;
  outline: none;
}

.cancel-btn {
  color: rgb(107 114 128);
  background: #fff;
  border: 1px solid rgb(229 231 235);
}
.cancel-btn:hover {
  color: rgb(75 85 99);
  background: rgb(249 250 251);
  border-color: rgb(209 213 219);
}
.cancel-btn:active {
  transform: scale(0.97);
}

.primary-btn {
  color: #fff;
  background: linear-gradient(135deg, #b3b8fd 0%, #7083ff 100%);
  box-shadow: 0 2px 8px rgba(112, 131, 255, 0.3);
}
.primary-btn:hover {
  box-shadow: 0 4px 14px rgba(112, 131, 255, 0.4);
  filter: brightness(1.05);
}
.primary-btn:active {
  transform: scale(0.97);
}
.primary-btn:disabled {
  opacity: 0.7;
  cursor: not-allowed;
}

.danger-btn {
  background: linear-gradient(135deg, #fca5a5 0%, #ef4444 100%);
  box-shadow: 0 2px 8px rgba(239, 68, 68, 0.3);
}
.danger-btn:hover {
  box-shadow: 0 4px 14px rgba(239, 68, 68, 0.4);
}
.warning-btn {
  background: linear-gradient(135deg, #ffa500 0%, #ff8c00 100%);
  box-shadow: 0 2px 8px rgba(255, 165, 0, 0.3);
}
.warning-btn:hover {
  box-shadow: 0 4px 14px rgba(255, 165, 0, 0.4);
}
</style>
