<template>
  <el-dialog
    v-model="visible"
    :title="title"
    :width="isFullscreen ? '100%' : width"
    :append-to-body="draggable || appendToBody"
    :draggable="draggable"
    :destroy-on-close="destroyOnClose"
    :class="['flex flex-col', customClass]"
    :align-center="alignCenter"
    :top="dialogTop"
    :center="center"
    :fullscreen="isFullscreen"
    v-bind="$attrs"
    :style="isFullscreen ? { maxWidth: 'none' } : {}"
    @close="handleClose"
  >
    <template #header>
      <button v-if="showFullscreen" class="dialog-fullscreen">
        <SvgIcon :name="isFullscreen ? 'fullscreen-exit' : 'fullscreen'" :size="18" @click="handleFullscreen" />
      </button>
      <slot v-if="$slots.header" name="header" />
      <div v-else :class="{ 'px-6': isFullscreen && center }">
        <span class="el-dialog__title">{{ title }}</span>
      </div>
    </template>
    <slot />
    <template v-if="$slots.footer" #footer>
      <slot name="footer" />
    </template>
    <template v-else-if="showFooter" #footer>
      <div class="flex justify-end">
        <el-button v-if="showCancelButton" @click="handleCancel">
          {{ cancelButtonText }}
        </el-button>
        <el-button v-if="showConfirmButton" type="primary" :loading="confirmLoading" @click="handleConfirm">
          {{ confirmButtonText }}
        </el-button>
      </div>
    </template>
  </el-dialog>
</template>

<script setup lang="ts">
import { addUnit } from '@/utils/util'

// 定义组件属性
const props = withDefaults(
  defineProps<{
    // 对话框是否可见
    modelValue: boolean
    // 对话框标题
    title?: string
    // 对话框宽度
    width?: string | number
    // 是否将对话框添加到 body 元素
    appendToBody?: boolean
    // 是否可拖动
    draggable?: boolean
    // 是否在关闭时销毁 DOM 元素
    destroyOnClose?: boolean
    // 自定义类名
    customClass?: string
    // 是否居中对齐
    alignCenter?: boolean
    // 对话框顶部距离
    top?: string | number
    // 是否居中对齐标题
    center?: boolean
    // 是否显示底部按钮
    showFooter?: boolean
    // 是否全屏显示
    fullscreen?: boolean
    // 是否显示全屏按钮
    showFullscreen?: boolean
    // 是否显示取消按钮
    showCancelButton?: boolean
    // 是否显示确认按钮
    showConfirmButton?: boolean
    // 取消按钮文字
    cancelButtonText?: string
    // 确认按钮文字
    confirmButtonText?: string
    // 确认按钮加载状态
    confirmLoading?: boolean
  }>(),
  {
    title: '提示',
    width: '500px',
    appendToBody: true,
    draggable: false,
    destroyOnClose: true,
    customClass: '',
    alignCenter: true,
    top: '15vh',
    center: false,
    showFooter: true,
    fullscreen: false,
    showFullscreen: false,
    showCancelButton: true,
    showConfirmButton: true,
    cancelButtonText: '取消',
    confirmButtonText: '确定',
    confirmLoading: false
  }
)

// 定义组件事件
const emit = defineEmits<{
  // v-model 双向绑定事件
  (event: 'update:modelValue', value: boolean): void
  // 取消按钮点击事件
  (event: 'cancel'): void
  // 确认按钮点击事件
  (event: 'confirm'): void
  // 对话框关闭事件
  (event: 'close'): void
  // 全屏切换事件
  (event: 'changeFullscreen', value: boolean): void
}>()

// 对话框可见性
const visible = ref(props.modelValue)

// 是否全屏显示
const isFullscreen = computed(() => {
  if (props.showFullscreen) return fullscreenState.value
  else return props.fullscreen
})

// 对话框顶部距离
const dialogTop = computed(() => {
  return addUnit(props.top) as string
})

// 全屏变量
const fullscreenState = ref(props.fullscreen)

// 监听外部 modelValue 变化
watch(
  () => props.modelValue,
  (newVal) => {
    visible.value = newVal
  }
)

// 监听内部 visible 变化
watch(visible, (newVal) => {
  emit('update:modelValue', newVal)
})

// 全屏切换事件
const handleFullscreen = () => {
  fullscreenState.value = !fullscreenState.value
  emit('changeFullscreen', fullscreenState.value)
}

// 取消按钮点击事件
const handleCancel = () => {
  emit('cancel')
  visible.value = false
}

// 确认按钮点击事件
const handleConfirm = () => {
  emit('confirm')
}

// 对话框关闭事件
const handleClose = () => {
  emit('close')
}
</script>

<style lang="scss" scoped>
.dialog-fullscreen {
  @apply absolute right-12 cursor-pointer duration-300 leading-none;
  height: 48px;
  top: 0;
  color: var(--el-color-info);
  display: flex;
  align-items: center;

  &:hover {
    color: var(--el-color-primary);
  }
}
</style>
