<template>
  <el-dialog
    v-model="dialogVisible"
    :title="displayFileName"
    width="70%"
    :close-on-click-modal="false"
    destroy-on-close
    @close="handleClose"
  >
    <div class="preview-container">
      <!-- 图片预览 -->
      <div v-if="previewType === 'image'" class="preview-image-wrapper">
        <img :src="previewUrl" class="preview-image" alt="预览图片" />
      </div>

      <!-- PDF 预览 -->
      <iframe
        v-else-if="previewType === 'pdf'"
        :src="previewUrl"
        class="preview-pdf"
        frameborder="0"
      ></iframe>

      <!-- 不支持预览 -->
      <div v-else-if="previewType === 'unsupported'" class="preview-unsupported">
        <el-icon :size="48" color="#909399"><Document /></el-icon>
        <p>暂不支持预览此类型文件</p>
        <el-button type="primary" @click="handleClose">关闭</el-button>
      </div>
    </div>
  </el-dialog>
</template>

<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { Document } from '@element-plus/icons-vue'

// --- Props 定义 ---
interface Props {
  modelValue: boolean // 控制弹窗显示/隐藏（支持 v-model）
  fileUrl: string // 文件 URL 或 Blob URL
  fileName?: string // 文件名（用于弹窗标题及类型推断）
  fileType?: 'image' | 'pdf' | 'unsupported' // 手动指定文件类型（可选）
}

const props = withDefaults(defineProps<Props>(), {
  fileName: '文件预览',
  fileType: undefined
})

// --- Emits 定义 ---
const emit = defineEmits<{
  (e: 'update:modelValue', value: boolean): void
  (e: 'close'): void
}>()

// --- 内部状态 ---
// 用于实际绑定到 img/iframe 的 URL，关闭时会清空
const previewUrl = ref('')

// 弹窗显示状态（双向绑定）
const dialogVisible = computed({
  get: () => props.modelValue,
  set: val => emit('update:modelValue', val)
})

// 最终显示的标题
const displayFileName = computed(() => props.fileName || '文件预览')

// --- 文件类型推断 ---
const previewType = computed<'image' | 'pdf' | 'unsupported'>(() => {
  // 1. 若外部显式传入 fileType，优先使用
  if (props.fileType) {
    return props.fileType
  }

  // 2. 根据 fileUrl 或 fileName 的后缀名自动判断
  const url = props.fileUrl || ''
  const name = props.fileName || ''
  const lowerUrl = url.toLowerCase()
  const lowerName = name.toLowerCase()

  const imageExts = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp', '.svg']
  const isImage = (str: string) => imageExts.some(ext => str.endsWith(ext))
  const isPdf = (str: string) => str.endsWith('.pdf')

  if (isImage(lowerUrl) || isImage(lowerName)) return 'image'
  if (isPdf(lowerUrl) || isPdf(lowerName)) return 'pdf'
  return 'unsupported'
})

// --- 同步外部 URL 到预览 URL ---
// 当弹窗打开时，将 fileUrl 赋值给 previewUrl
// 当弹窗关闭时，清空 previewUrl，释放资源
watch(
  () => props.modelValue,
  visible => {
    if (visible && props.fileUrl) {
      previewUrl.value = props.fileUrl
    } else if (!visible) {
      previewUrl.value = ''
    }
  },
  { immediate: true }
)

// 如果弹窗已打开但 fileUrl 发生变化（例如父组件动态修改），同步更新预览内容
watch(
  () => props.fileUrl,
  newUrl => {
    if (dialogVisible.value && newUrl) {
      previewUrl.value = newUrl
    }
  }
)

// --- 关闭处理 ---
const handleClose = () => {
  dialogVisible.value = false // 关闭弹窗
  previewUrl.value = '' // 清空预览地址
  emit('close') // 通知父组件
}
</script>

<style scoped>
.preview-container {
  width: 100%;
  min-height: 400px;
  display: flex;
  justify-content: center;
  align-items: center;
}

.preview-image-wrapper {
  width: 100%;
  text-align: center;
}

.preview-image {
  max-width: 100%;
  max-height: 70vh;
  object-fit: contain;
}

.preview-pdf {
  width: 100%;
  height: 70vh;
}

.preview-unsupported {
  text-align: center;
  padding: 40px;
}

.preview-unsupported p {
  margin: 20px 0;
  color: #909399;
}
</style>
