<template>
  <ElDialog v-model="visible" title="凭证查看" width="560px" @closed="handleClose">
    <div v-if="loading" class="voucher-preview__loading">加载中...</div>
    <div v-else-if="files.length" class="voucher-preview__list">
      <div v-for="file in files" :key="file.key" class="voucher-preview__item">
        <ElImage
          v-if="file.isImage"
          class="voucher-preview__image"
          :src="file.url"
          :preview-src-list="imageUrls"
          :initial-index="getImageIndex(file.url)"
          fit="cover"
          preview-teleported
        />
        <div v-else class="voucher-preview__file">
          <ElIcon><component :is="getFileIcon(file)" /></ElIcon>
          <span class="voucher-preview__file-type">{{ file.fileType }}</span>
        </div>
        <div class="voucher-preview__meta">
          <div class="voucher-preview__name" :title="file.name">{{
            getDisplayName(file.name)
          }}</div>
          <ElButton link type="primary" @click="openFile(file)">查看/下载</ElButton>
        </div>
      </div>
    </div>
    <ElEmpty v-else description="暂无凭证" />
  </ElDialog>
</template>

<script setup lang="ts">
  import { computed, ref, watch } from 'vue'
  import {
    Box,
    DataAnalysis,
    Document,
    Film,
    Headset,
    Memo,
    Picture,
    Tickets
  } from '@element-plus/icons-vue'
  import { ElButton, ElDialog, ElEmpty, ElIcon, ElImage } from 'element-plus'
  import type { Component } from 'vue'
  import { StorageService } from '@/api/modules'
  import { toVoucherKeyList } from '@/utils/business'

  interface Props {
    fileKey?: string | string[]
    fileKeys?: string[]
  }

  interface VoucherFile {
    key: string
    name: string
    url: string
    isImage: boolean
    extension: string
    fileType: string
  }

  const props = defineProps<Props>()

  const emit = defineEmits<{
    close: []
  }>()

  const visible = ref(false)
  const loading = ref(false)
  const files = ref<VoucherFile[]>([])

  const imageUrls = computed(() =>
    files.value.filter((file) => file.isImage).map((file) => file.url)
  )

  const getFileName = (fileKey: string) => fileKey.split('/').pop() || fileKey

  const getFileExtension = (fileName: string) => {
    const match = fileName.toLowerCase().match(/\.([a-z0-9]+)(?:[?#].*)?$/)
    return match?.[1] || ''
  }

  const getFileType = (extension: string) => {
    if (!extension) return '文件'
    const typeMap: Record<string, string> = {
      csv: 'CSV',
      xls: 'Excel',
      xlsx: 'Excel',
      doc: 'Word',
      docx: 'Word',
      pdf: 'PDF',
      txt: 'TXT',
      json: 'JSON',
      zip: 'ZIP',
      rar: 'RAR',
      '7z': '7Z',
      mp4: '视频',
      mov: '视频',
      avi: '视频',
      mp3: '音频',
      wav: '音频'
    }
    return typeMap[extension] || extension.toUpperCase()
  }

  const getDisplayName = (fileName: string) => {
    if (fileName.length <= 28) return fileName

    const extension = getFileExtension(fileName)
    const suffix = extension ? `.${extension}` : ''
    const baseName = suffix ? fileName.slice(0, -suffix.length) : fileName
    if (baseName.length <= 22) return fileName

    return `${baseName.slice(0, 12)}...${baseName.slice(-8)}${suffix}`
  }

  const isImageFile = (fileKey: string, url: string) => {
    const target = `${fileKey} ${url}`.toLowerCase()
    return /\.(png|jpe?g|gif|webp|bmp|svg)(\?|#|$)/.test(target)
  }

  const getImageIndex = (url: string) => Math.max(0, imageUrls.value.indexOf(url))

  const getFileIcon = (file: VoucherFile): Component => {
    const iconMap: Record<string, Component> = {
      csv: DataAnalysis,
      xls: DataAnalysis,
      xlsx: DataAnalysis,
      doc: Tickets,
      docx: Tickets,
      pdf: Document,
      txt: Memo,
      json: Memo,
      zip: Box,
      rar: Box,
      '7z': Box,
      mp4: Film,
      mov: Film,
      avi: Film,
      mp3: Headset,
      wav: Headset,
      png: Picture,
      jpg: Picture,
      jpeg: Picture,
      gif: Picture,
      webp: Picture,
      bmp: Picture,
      svg: Picture
    }
    return iconMap[file.extension] || Document
  }

  const openFile = (file: VoucherFile) => {
    window.open(file.url, '_blank', 'noopener,noreferrer')
  }

  watch(
    () => [props.fileKeys, props.fileKey] as const,
    async ([fileKeys, fileKey]) => {
      const keys = fileKeys?.length ? toVoucherKeyList(fileKeys) : toVoucherKeyList(fileKey)

      if (!keys.length) {
        visible.value = false
        files.value = []
        return
      }

      visible.value = true
      loading.value = true
      files.value = []

      try {
        const res = await StorageService.batchDownloadUrls({
          file_keys: keys
        })
        if (res.code === 0) {
          files.value = keys
            .map((key) => {
              const url = res.data.urls[key]
              if (!url) return null
              return {
                key,
                name: getFileName(key),
                url,
                isImage: isImageFile(key, url),
                extension: getFileExtension(getFileName(key)),
                fileType: getFileType(getFileExtension(getFileName(key)))
              }
            })
            .filter((file): file is VoucherFile => !!file)
        }
      } catch (error) {
        console.error('获取凭证失败:', error)
      } finally {
        loading.value = false
      }
    },
    { immediate: true }
  )

  const handleClose = () => {
    visible.value = false
    loading.value = false
    files.value = []
    emit('close')
  }
</script>

<style scoped lang="scss">
  .voucher-preview {
    &__loading {
      padding: 32px 0;
      color: var(--el-text-color-secondary);
      text-align: center;
    }

    &__list {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
      gap: 12px;
    }

    &__item {
      min-width: 0;
    }

    &__image,
    &__file {
      width: 120px;
      height: 120px;
      border: 1px solid var(--el-border-color-light);
      border-radius: 8px;
    }

    &__image {
      cursor: zoom-in;
    }

    &__file {
      display: flex;
      flex-direction: column;
      gap: 8px;
      align-items: center;
      justify-content: center;
      font-size: 40px;
      color: var(--el-text-color-secondary);
      background: var(--el-fill-color-light);
    }

    &__file-type {
      max-width: 84px;
      overflow: hidden;
      font-size: 12px;
      font-weight: 600;
      line-height: 16px;
      color: var(--el-text-color-regular);
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    &__meta {
      width: 120px;
      margin-top: 8px;
    }

    &__name {
      overflow: hidden;
      font-size: 12px;
      line-height: 18px;
      color: var(--el-text-color-regular);
      text-overflow: ellipsis;
      white-space: nowrap;
    }
  }
</style>
