<script lang="ts" setup>
import { ref } from 'vue';

import { ElImageViewer } from 'element-plus';

// 定义组件props
interface Props {
  // 文件URL数组
  files: string[];
  // 文件名称数组（可选）
  fileNames?: string[];
  // 图片预览是否启用
  previewEnabled?: boolean;
  // 下载是否启用
  downloadEnabled?: boolean;
}

const props = withDefaults(defineProps<Props>(), {
  files: () => [],
  fileNames: () => [],
  previewEnabled: true,
  downloadEnabled: true,
});

// 图片预览相关
const previewVisible = ref(false);
const previewImages = ref<string[]>([]);

// 预览图片
const previewImage = (imageUrl: string) => {
  if (!props.previewEnabled) return;
  previewImages.value = [imageUrl];
  previewVisible.value = true;
};

// 关闭图片预览
const closePreview = () => {
  previewVisible.value = false;
};

// 下载文件
const downloadFile = (fileUrl: string, fileName: string) => {
  if (!props.downloadEnabled) return;
  // 创建临时链接
  const link = document.createElement('a');
  // 设置下载属性，强制所有文件下载
  link.download = fileName;
  // 使用 rel="noopener noreferrer" 提高安全性
  link.rel = 'noopener noreferrer';
  // 对于图片等浏览器会直接打开的文件，使用 fetch 方式获取 blob 再下载
  fetch(fileUrl)
    .then((response) => response.blob())
    .then((blob) => {
      // 创建 blob URL
      const blobUrl = URL.createObjectURL(blob);
      link.href = blobUrl;
      // 触发下载
      document.body.append(link);
      link.click();
      // 清理
      link.remove();
      // 释放 blob URL
      setTimeout(() => {
        URL.revokeObjectURL(blobUrl);
      }, 100);
    })
    .catch((error) => {
      console.error('下载失败:', error);
      // 如果 fetch 失败，回退到直接下载
      link.href = fileUrl;
      document.body.append(link);
      link.click();
      link.remove();
    });
};

// 图片类型扩展名
const imageExtensions = new Set([
  'bmp',
  'gif',
  'jpeg',
  'jpg',
  'png',
  'svg',
  'webp',
]);

// 文件类型图标映射
const fileTypeIcons: Record<string, string> = {
  // 图片类型
  jpg: '📷',
  jpeg: '📷',
  png: '📷',
  gif: '📷',
  bmp: '📷',
  webp: '📷',
  svg: '📷',
  // 文档类型
  doc: '📄',
  docx: '📄',
  pdf: '📄',
  txt: '📄',
  md: '📄',
  // 表格类型
  xls: '📊',
  xlsx: '📊',
  csv: '📊',
  // 演示文稿类型
  ppt: '📺',
  pptx: '📺',
  // 压缩文件类型
  zip: '📦',
  rar: '📦',
  '7z': '📦',
  tar: '📦',
  gz: '📦',
  // 其他类型
  default: '📁',
};

// 获取文件扩展名
const getFileExtension = (url: string): string => {
  // 移除URL参数
  const cleanUrl = url.split('?')[0];
  // 获取最后一个点后的内容作为扩展名
  const parts = cleanUrl.split('.');
  if (parts.length < 2) return 'default';
  return parts[parts.length - 1].toLowerCase();
};

// 判断是否为图片
const isImage = (url: string): boolean => {
  const extension = getFileExtension(url);
  return imageExtensions.has(extension);
};

// 获取文件图标
const getFileIcon = (url: string): string => {
  const extension = getFileExtension(url);
  return fileTypeIcons[extension] || fileTypeIcons.default;
};

// 获取文件名
const getFileName = (url: string, index: number): string => {
  if (props.fileNames && props.fileNames[index]) {
    return props.fileNames[index];
  }
  // 从URL中提取文件名
  const cleanUrl = url.split('?')[0];
  const parts = cleanUrl.split('/');
  const fileName = parts[parts.length - 1];
  return fileName || `附件${index + 1}`;
};

// 获取文件类型显示文本
const getFileTypeText = (url: string): string => {
  const extension = getFileExtension(url);
  return extension.toUpperCase() || 'FILE';
};
</script>

<template>
  <div class="attachment-viewer">
    <div
      v-for="(file, index) in files"
      :key="index"
      class="attachment-item"
      :class="{ 'is-image': isImage(file) }"
      @click="
        isImage(file)
          ? previewImage(file)
          : downloadFile(file, getFileName(file, index))
      "
    >
      <!-- 图片显示 -->
      <img
        v-if="isImage(file)"
        :src="file"
        :alt="getFileName(file, index)"
        class="attachment-image"
      />

      <!-- 非图片文件显示 -->
      <div v-else class="attachment-file">
        <div class="file-icon">{{ getFileIcon(file) }}</div>
        <div class="file-type">{{ getFileTypeText(file) }}</div>
      </div>

      <!-- 文件名显示 -->
      <div class="attachment-name">{{ getFileName(file, index) }}</div>
    </div>

    <!-- 图片预览组件 -->
    <ElImageViewer
      v-if="previewVisible"
      :url-list="previewImages"
      @close="closePreview"
    />
  </div>
</template>

<style scoped lang="scss">
.attachment-viewer {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 4px;
}

.attachment-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 60px;
  height: 60px;
  cursor: pointer;
  border-radius: 4px;
  transition: all 0.2s ease;
  overflow: hidden;
  position: relative;

  &:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  }

  // 图片项样式
  &.is-image {
    .attachment-image {
      width: 100%;
      height: 100%;
      object-fit: cover;
      border-radius: 4px;
    }
  }

  // 非图片文件项样式
  .attachment-file {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background-color: #f8f9fa;
    border: 1px solid #e9ecef;
    border-radius: 4px;

    .file-icon {
      font-size: 24px;
      margin-bottom: 4px;
    }

    .file-type {
      font-size: 10px;
      color: #6c757d;
      text-transform: uppercase;
    }
  }

  // 文件名样式
  .attachment-name {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    padding: 2px 4px;
    background-color: rgba(0, 0, 0, 0.6);
    color: white;
    font-size: 10px;
    text-align: center;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    opacity: 0;
    transition: opacity 0.2s ease;

    .attachment-item:hover & {
      opacity: 1;
    }
  }
}

// 响应式布局
@media (max-width: 768px) {
  .attachment-viewer {
    gap: 8px;
  }

  .attachment-item {
    width: 50px;
    height: 50px;
  }

  .attachment-file {
    .file-icon {
      font-size: 20px;
    }

    .file-type {
      font-size: 9px;
    }
  }
}

@media (max-width: 480px) {
  .attachment-item {
    width: 40px;
    height: 40px;
  }

  .attachment-file {
    .file-icon {
      font-size: 16px;
    }

    .file-type {
      font-size: 8px;
    }
  }
}
</style>
