<script setup>
// 导入所需的API和组件
import { uploadImg } from "@/api-norm/common/index.js";
import { ref, shallowRef, watch, onMounted, computed, useAttrs, useId } from "vue";
import { previewImage } from "@/components/x-naive-ui/x-preview-img/index.ts";
import { isEqual } from "lodash-es";
import { useMessage } from "naive-ui";

/**
 * 文件类型配置对象
 * 定义了不同文件类型的正则匹配模式和默认封面
 */
const FileTypes = {
  IMAGE: {
    pattern: /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i,
    defaultCover: ""
  },
  VIDEO: {
    pattern: /\.(mp4|webm|ogg|avi|mov|mkv|flv|wmv)$/i,
    defaultCover: new URL(`@/icons/video.svg`, import.meta.url).href
  },
  PDF: {
    pattern: /\.pdf$/i,
    defaultCover: new URL("@/icons/Pdf.svg", import.meta.url).href
  }
};

// 组件属性定义
const props = defineProps({
  // 视频封面字段名
  fieldCover: {
    type: String,
    default: "coverUrl"
  },
  // 视频URL字段名
  fieldVideo: {
    type: String,
    default: "videoUrl"
  },
  // 值格式：array或simple
  valueFormat: {
    type: String,
    default: "array"
  },
  // 上传项宽度
  itemWidth: {
    type: [String, Number],
    default: "120px"
  },
  // 上传项高度
  itemHeight: {
    type: [String, Number],
    default: "120px"
  },
  // 组件值
  value: {
    type: [String, Array],
    default: () => []
  },
  // 最大重试次数
  maxRetries: {
    type: Number,
    default: 3
  },
  // 最大上传数量
  max: {
    type: Number,
    default: 9
  },
  // 是否允许多文件选择
  multiple: {
    type: Boolean,
    default: false
  },
  // 是否禁用
  disabled: {
    type: Boolean,
    default: false
  },
  // 最大文件大小(B)
  maxSize: {
    type: Number,
    default: 0
  },
  // 接受的文件类型
  accept: {
    type: String,
    default: ""
  },
  // 是否显示下载按钮
  showDownload: {
    type: Boolean,
    default: false
  },
  // 是否显示删除按钮
  showDelete: {
    type: Boolean,
    default: true
  }
});

// 定义事件
const emit = defineEmits([
  'update:value', 
  'before-upload', 
  'upload-error', 
  'change',
  'download',
  'preview',
  'remove'
]);

// 组件状态变量
const isUploading = ref(false);
const message = useMessage();
const attrs = useAttrs();
const fileCache = new WeakMap();
const fileList = shallowRef([]);
const showPreview = ref(false);
const previewVideoUrl = ref("");
const previousValue = ref();
const retryingFiles = shallowRef({});
const inputFileRef = ref(null);
const dragActive = ref(false);
const instanceId = useId();

/**
 * 通用文件处理工具
 * 提供文件类型检测和处理功能
 */
const FileUtils = {
  /**
   * 检查文件URL是否符合指定类型
   * @param {string} url - 文件URL
   * @param {string} type - 文件类型 (IMAGE, VIDEO, PDF)
   * @returns {boolean} - 是否符合类型
   */
  isFileType(url, type) {
    if (!url) return false;
    return FileTypes[type].pattern.test(url.toLowerCase ? url.toLowerCase() : "");
  },
  
  /**
   * 获取文件对象的类型
   * @param {Object} file - 文件对象
   * @returns {string} - 文件类型 (video, image, pdf)
   */
  getFileType(file) {
    if (!file.name && !file.url) return "image";

    const testPath = file.name || file.url;
    
    // 如果缓存中有该文件的类型，直接返回
    if (fileCache.has(file)) {
      return fileCache.get(file);
    }
    
    // 根据文件路径判断类型
    let type = "image";
    
    if (this.isFileType(testPath, "VIDEO")) {
      type = "video";
    } else if (this.isFileType(testPath, "PDF")) {
      type = "pdf";
    }
    
    // 缓存文件类型
    fileCache.set(file, type);
    return type;
  },
  
  /**
   * 创建文件对象
   * @param {string} url - 文件URL
   * @param {string|null} name - 文件名称
   * @returns {Object} - 文件对象
   */
  createFileObject(url, name = null) {
    return {
      url,
      name,
      status: "finished",
      id: Math.random().toString(36).substring(2, 10)
    };
  },
  
  /**
   * 处理文件项
   * @param {Object|string} item - 文件项
   * @param {string} fileType - 文件类型 (video, image, pdf)
   * @returns {Object|null} - 处理后的文件对象
   */
  processFileItem(item, fileType) {
    // 处理视频文件
    if (fileType === "video") {
      return this.processVideoFile(item);
    }
    
    // 处理图片或PDF文件
    return this.processImageOrPdf(item);
  },
  
  /**
   * 处理视频文件
   * @param {Object|string} item - 视频项
   * @returns {Object|null} - 处理后的文件对象
   */
  processVideoFile(item) {
    if (typeof item === "object") {
      return this.createFileObject(
        item[props.fieldCover] || FileTypes.VIDEO.defaultCover,
        item[props.fieldVideo]
      );
    }
    
    if (typeof item === "string" && isVideo(item)) {
      return this.createFileObject(FileTypes.VIDEO.defaultCover, item);
    }
    
    return null;
  },
  
  /**
   * 处理图片或PDF文件
   * @param {string} value - 文件URL
   * @returns {Object|null} - 处理后的文件对象
   */
  processImageOrPdf(value) {
    if (isPDF(value)) {
      return this.createFileObject(FileTypes.PDF.defaultCover, value);
    }
    
    if (isImage(value)) {
      return this.createFileObject(value);
    }
    
    return null;
  },
  
  /**
   * 处理文件列表
   * @param {Array|Object|string} value - 文件或列表
   * @param {string} fileType - 文件类型 (video, image, pdf)
   * @returns {Array} - 处理后的文件对象数组
   */
  processFileList(value, fileType) {
    // 如果值为空，返回空数组
    if (!value) return [];
    
    // 如果不是数组，处理单个文件项
    if (!Array.isArray(value)) {
      const result = this.processFileItem(value, fileType);
      return result ? [result] : [];
    }
    
    // 处理数组中的每个文件项
    const results = [];
    for (let i = 0; i < value.length; i++) {
      const result = this.processFileItem(value[i], fileType);
      if (result !== null) {
        results.push(result);
      }
    }
    
    return results;
  }
};

/**
 * 检查文件URL是否符合图片类型
 * @param {string} url - 文件URL
 * @returns {boolean} - 是否为图片
 */
function isImage(url) {
  return FileUtils.isFileType(url, "IMAGE");
}

/**
 * 检查文件URL是否符合视频类型
 * @param {string} url - 文件URL
 * @returns {boolean} - 是否为视频
 */
function isVideo(url) {
  return FileUtils.isFileType(url, "VIDEO");
}

/**
 * 检查文件URL是否符合PDF类型
 * @param {string} url - 文件URL
 * @returns {boolean} - 是否为PDF
 */
function isPDF(url) {
  return FileUtils.isFileType(url, "PDF");
}

/**
 * 获取文件对象的类型
 * @param {Object} file - 文件对象
 * @returns {string} - 文件类型
 */
function getFileType(file) {
  // 如果已经缓存过类型，直接返回
  if (fileCache.has(file)) {
    return fileCache.get(file);
  }
  
  const testPath = file.name || file.url;
  if (!testPath) return "image";
  
  let type = "image";
  
  // 使用一次循环处理所有类型检测
  const lowerPath = testPath.toLowerCase();
  
  // 按优先级检查类型（先检查更常见的类型）
  if (FileTypes.IMAGE.pattern.test(lowerPath)) {
    type = "image";
  } else if (FileTypes.PDF.pattern.test(lowerPath)) {
    type = "pdf";
  } else if (FileTypes.VIDEO.pattern.test(lowerPath)) {
    type = "video";
  }
  
  // 缓存并返回结果
  fileCache.set(file, type);
  return type;
}

/**
 * 处理视频文件列表
 * @param {Array|Object} value - 视频文件或列表
 * @returns {Array} - 处理后的文件对象数组
 */
function handleVideoFiles(value) {
  return FileUtils.processFileList(value, "video");
}

/**
 * 处理图片和PDF文件列表
 * @param {string|Array} value - 文件URL或列表
 * @returns {Array} - 处理后的文件对象数组
 */
function handleImageAndPdf(value) {
  // 如果值为空，返回空数组
  if (!value) return [];
  
  // 如果是字符串，处理单个文件
  if (typeof value === "string") {
    if (isPDF(value)) {
      return [FileUtils.createFileObject(FileTypes.PDF.defaultCover, value)];
    }
    
    if (isImage(value)) {
      return [FileUtils.createFileObject(value)];
    }
    
    return [];
  }
  
  // 处理数组中的每个文件
  const results = [];
  for (let i = 0; i < value.length; i++) {
    const item = value[i];
    if (isPDF(item)) {
      results.push(FileUtils.createFileObject(FileTypes.PDF.defaultCover, item));
    } else if (isImage(item)) {
      results.push(FileUtils.createFileObject(item));
    }
  }
  
  return results;
}

/**
 * 上传处理器对象
 * 处理文件上传相关的所有操作
 */
const UploadHandler = {
  /**
   * 处理文件上传
   * @param {File} file - 文件对象
   * @returns {Promise<void>}
   */
  async uploadFile(file) {
    try {
      console.log("开始上传文件:", file.name);
      
      // 创建内部文件对象
      const fileObj = {
        id: Math.random().toString(36).substring(2, 10),
        name: file.name,
        size: file.size, 
        type: file.type,
        status: "uploading",
        file: file,
        percentage: 0
      };
      
      // 添加到文件列表
      fileList.value = [...fileList.value, fileObj];
      
      // 开始上传
      isUploading.value = true;
      
      // 初始化重试计数
      retryingFiles.value = {
        ...retryingFiles.value,
        [fileObj.id]: { count: 0, status: 'uploading' }
      };
      
      // 调用上传API
      await this.processUpload(fileObj);
      
    } catch (error) {
      console.error("Upload error:", error);
      message.error("上传失败，请重试");
    } finally {
      isUploading.value = false;
    }
  },
  
  /**
   * 处理上传过程
   * @param {Object} fileObj - 文件对象
   * @returns {Promise<void>}
   */
  async processUpload(fileObj) {
    try {
      console.log("处理上传过程:", fileObj.name);
      
      // 创建表单数据
      const formData = new FormData();
      formData.append("file", fileObj.file);
      formData.append("source", "artwork");
      
      if (fileObj.type && fileObj.type.includes("video")) {
        formData.append("type", "video");
      }
      
      console.log("表单数据准备完成，开始调用上传API");
      
      // 上传文件
      const response = await uploadImg(formData, {
        onUploadProgress: (progressEvent) => {
          const percent = Math.round((progressEvent.loaded * 100) / progressEvent.total);
          console.log(`上传进度: ${percent}%`);
          this.updateFileProgress(fileObj.id, percent);
        }
      });
      
      console.log("上传API响应:", response);
      
      // 处理响应
      if (response.status !== 0) {
        throw new Error("Upload failed with status: " + response.status);
      }
      
      // 上传成功处理
      this.handleUploadSuccess(fileObj, response.data);
      
    } catch (error) {
      console.error("处理上传过程出错:", error);
      // 处理上传错误
      await this.handleUploadError(error, fileObj);
    }
  },
  
  /**
   * 更新上传进度
   * @param {string} fileId - 文件ID
   * @param {number} percent - 进度百分比
   */
  updateFileProgress(fileId, percent) {
    fileList.value = fileList.value.map(item => {
      if (item.id === fileId) {
        return { ...item, percentage: percent };
      }
      return item;
    });
    
    // 触发change事件
    emit('change', { fileList: fileList.value });
  },
  
  /**
   * 处理上传成功
   * @param {Object} fileObj - 文件对象
   * @param {Object} data - 响应数据
   */
  handleUploadSuccess(fileObj, data) {
    // 更新文件状态
    fileList.value = fileList.value.map(item => {
      if (item.id === fileObj.id) {
        const updatedItem = { ...item, status: "finished", percentage: 100 };
        
        // 处理视频文件
        if (item.type && item.type.includes("video")) {
          updatedItem.url = data.cover_url || FileTypes.VIDEO.defaultCover;
          updatedItem.name = data.ori_url;
          
          // 设置封面图片的扩展名
          let extension = "jpg";
          if (data.cover_url) {
            const parts = data.cover_url.split(".");
            if (parts.length > 1) {
              const lastPart = parts[parts.length - 1];
              extension = lastPart.split("?")[0] || "jpg";
            }
          }
          
          updatedItem.type = `image/${extension}`;
        } 
        // 处理PDF文件
        else if (item.type && item.type.includes("pdf")) {
          updatedItem.url = FileTypes.PDF.defaultCover;
          updatedItem.name = data.ori_url;
          updatedItem.type = "image/png";
        } 
        // 处理图片文件
        else {
          updatedItem.url = data.ori_url;
        }
        
        return updatedItem;
      }
      return item;
    });
    
    // 清除重试状态
    if (retryingFiles.value[fileObj.id]) {
      const { count } = retryingFiles.value[fileObj.id];
      retryingFiles.value = {
        ...retryingFiles.value,
        [fileObj.id]: { count, status: 'success' }
      };
      
      // 如果之前有重试，显示成功消息
      if (count > 0) {
        message.success(`文件 "${fileObj.name}" 上传成功 (重试 ${count} 次后)`);
      }
    }
    
    // 更新组件值
    updateFileList();
    message.success("上传成功");
    emit('change', { fileList: fileList.value });
  },
  
  /**
   * 处理上传错误
   * @param {Error} error - 错误对象
   * @param {Object} fileObj - 文件对象
   * @returns {Promise<void>}
   */
  async handleUploadError(error, fileObj) {
    const fileInfo = retryingFiles.value[fileObj.id] || { count: 0, status: 'error' };
    
    // 检查是否可以重试
    if (fileInfo.count < props.maxRetries) {
      // 更新重试计数
      retryingFiles.value = {
        ...retryingFiles.value,
        [fileObj.id]: { 
          count: fileInfo.count + 1, 
          status: 'retrying' 
        }
      };
      
      // 更新文件状态为重试中
      fileList.value = fileList.value.map(item => {
        if (item.id === fileObj.id) {
          return { ...item, status: "retrying", percentage: 0 };
        }
        return item;
      });
      
      // 显示重试消息
      message.info(`正在重试上传 "${fileObj.name}" (${fileInfo.count + 1}/${props.maxRetries})`);
      
      // 延迟一秒后重试
      await new Promise(resolve => setTimeout(resolve, 1000));
      
      try {
        // 重新上传
        await this.processUpload(fileObj);
        return;
      } catch (retryError) {
        console.error("Retry failed:", retryError);
        // 如果重试失败，继续处理错误
      }
    }
    
    // 如果重试次数已用完或重试失败，标记为失败
    retryingFiles.value = {
      ...retryingFiles.value,
      [fileObj.id]: { 
        count: fileInfo.count, 
        status: 'failed' 
      }
    };
    
    // 更新文件状态为失败
    fileList.value = fileList.value.map(item => {
      if (item.id === fileObj.id) {
        return { ...item, status: "error", percentage: 0 };
      }
      return item;
    });
    
    // 根据错误类型显示不同的错误消息
    let errorMessage = "上传失败";
    
    if (error.name === 'NetworkError' || error.message?.includes('network')) {
      errorMessage = "网络错误，请检查您的网络连接";
    } else if (error.name === 'TimeoutError' || error.message?.includes('timeout')) {
      errorMessage = "上传超时，服务器响应时间过长";
    } else if (error.response?.status === 413) {
      errorMessage = "文件太大，超出服务器接受的大小限制";
    } else if (error.response?.status === 403) {
      errorMessage = "没有权限上传文件";
    } else if (error.response?.status >= 500) {
      errorMessage = "服务器错误，请稍后重试";
    }
    
    // 显示错误消息
    message.error(`${fileObj.name}: ${errorMessage}`);
    
    // 触发错误事件
    emit('upload-error', { 
      file: fileObj, 
      error, 
      message: errorMessage,
      retries: fileInfo.count
    });
  }
};

/**
 * 验证文件类型
 * @param {File} file - 文件对象
 * @returns {boolean} - 是否有效
 */
function validateFileType(file) {
  const accept = props.accept;
  if (!accept) return true;

  // 将accept字符串转换为数组并规范化
  const acceptedTypes = [];
  const acceptParts = accept.split(',');
  
  for (let i = 0; i < acceptParts.length; i++) {
    let type = acceptParts[i].trim().toLowerCase();
    
    // 处理image/*这样的通配符格式
    if (type.endsWith('/*')) {
      type = type.split('/')[0];
    }
    
    // 处理.jpg, .pdf这样的具体格式
    if (type.startsWith('.')) {
      type = type.substring(1);
    }
    
    acceptedTypes.push(type);
  }

  // 获取文件类型和扩展名
  const fileType = file.type.toLowerCase().split('/')[0];
  const fileNameParts = file.name.split('.');
  const fileExtension = fileNameParts.length > 1 ? fileNameParts.pop().toLowerCase() : '';

  // 检查文件是否符合接受的类型
  for (let i = 0; i < acceptedTypes.length; i++) {
    const type = acceptedTypes[i];
    
    // 检查文件MIME类型
    if (fileType === type) return true;
    
    // 检查文件扩展名
    if (fileExtension === type) return true;
    
    // 检查完整的MIME类型
    if (file.type.toLowerCase() === type) return true;
  }
  
  return false;
}

/**
 * 验证文件大小
 * @param {File} file - 文件对象
 * @returns {boolean} - 是否有效
 */
function validateFileSize(file) {
  if (props.maxSize <= 0) return true;
  return file.size <= props.maxSize;
}

/**
 * 验证上传前的文件
 * @param {File} file - 文件对象
 * @returns {Promise<boolean>} - 是否允许上传
 */
async function validateBeforeUpload(file) {
  // 验证文件类型
  if (!validateFileType(file)) {
    message.error(`只能上传${props.accept}类型的文件`);
    return false;
  }
  
  // 验证文件大小
  if (!validateFileSize(file)) {
    const sizeInMB = props.maxSize / (1024 * 1024);
    message.error(`文件大小不能超过${sizeInMB.toFixed(2)}MB`);
    return false;
  }
  
  // 如果父组件定义了before-upload事件，则执行父组件的验证
  try {
    // 触发父组件的验证函数
    const result = emit('before-upload', { file });
    // emit不会返回值，所以我们不依赖结果，除非明确返回false
    return result !== false ? true : false;
  } catch (error) {
    console.error('执行父组件验证时出错:', error);
    return true; // 出错也允许上传
  }
}

/**
 * 计算样式
 * 缓存计算结果以提高性能
 */
const memoizedComputedStyles = computed(() => {
  /**
   * 为数值添加px单位（如果需要）
   * @param {string|number} value - 样式值
   * @returns {string} - 处理后的样式值
   */
  function addPxIfNeeded(value) {
    const strValue = String(value).trim();
    
    // 如果不包含单位，添加px
    if (!/\d+(px|em|rem|%)$/.test(strValue)) {
      return `${strValue}px`;
    }
    
    return strValue;
  }
  
  // 解析尺寸为数字（去掉单位）
  function parseSizeToNumber(size) {
    if (typeof size === 'number') return size;
    return parseInt(String(size).replace(/[^0-9]/g, ''));
  }
  
  const width = addPxIfNeeded(props.itemWidth);
  const height = addPxIfNeeded(props.itemHeight);
  
  // 根据容器尺寸计算加号大小、边框样式和操作按钮尺寸
  let plusSize = '24px';
  let borderStyle = '1px dashed #d9d9d9';
  let actionButtonSize = '32px';
  let actionIconSize = '16px';
  let progressFontSize = '12px';
  let progressBarHeight = '6px';
  
  const numWidth = parseSizeToNumber(props.itemWidth);
  
  if (numWidth <= 30) {
    plusSize = '12px';
    borderStyle = '1px solid #d9d9d9';
    actionButtonSize = '16px';
    actionIconSize = '10px';
    progressFontSize = '8px';
    progressBarHeight = '3px';
  } else if (numWidth <= 50) {
    plusSize = '16px';
    borderStyle = '1px solid #d9d9d9';
    actionButtonSize = '20px';
    actionIconSize = '12px';
    progressFontSize = '9px';
    progressBarHeight = '4px';
  } else if (numWidth <= 80) {
    plusSize = '20px';
    actionButtonSize = '24px';
    actionIconSize = '14px';
    progressFontSize = '10px';
    progressBarHeight = '5px';
  }
  
  return {
    fileWidth: width,
    fileHeight: height,
    uploadButton: {
      width: width,
      height: height,
      border: borderStyle
    },
    plusIconSize: plusSize,
    actionButtonSize: actionButtonSize,
    actionIconSize: actionIconSize,
    progressFontSize: progressFontSize,
    progressBarHeight: progressBarHeight
  };
});

/**
 * 更新文件列表并发出更新事件
 * 优化性能，减少循环次数
 */
function updateFileList() {
  const updatedFiles = [];
  let hasVideo = false;
  
  // 处理所有文件（单循环处理所有文件）
  for (let i = 0; i < fileList.value.length; i++) {
    const file = fileList.value[i];
    if (file.status !== "finished") continue;
    
    const type = getFileType(file);
    
    // 处理视频文件
    if (type === "video") {
      hasVideo = true;
      if (file.url === FileTypes.VIDEO.defaultCover) {
        updatedFiles.push(file.name);
      } else {
        const result = {
          [props.fieldVideo]: file.name,
          [props.fieldCover]: file.url
        };
        updatedFiles.push(result);
      }
    }
    // 处理PDF文件或图片文件
    else if (type === "pdf") {
      updatedFiles.push(file.name);
    }
    // 默认为图片文件
    else {
      updatedFiles.push(file.url);
    }
  }
  
  // 处理输出格式
  let updatedValue = updatedFiles;
  
  // 如果没有视频且格式为simple，尝试使用简单格式
  if (!hasVideo && props.valueFormat === "simple") {
    // 检查是否所有项都是字符串类型
    const isAllString = updatedFiles.every(item => typeof item === "string");
    
    if (isAllString) {
      updatedValue = updatedFiles.join(",");
    }
  }

  // 发出更新事件
  emit("update:value", updatedValue);
}

/**
 * 初始化文件列表
 * 根据props.value设置fileList
 */
function initFileList() {
  const newValue = props.value;
  
  // 如果值为空，清空文件列表
  if (!newValue || (Array.isArray(newValue) && !newValue.length)) {
    fileList.value = [];
    return;
  }

  /**
   * 检查当前值与新值是否相等
   * @returns {boolean} - 是否相等
   */
  function isValueEqual() {
    // 获取当前文件列表的值
    const currentValue = [];
    
    for (let i = 0; i < fileList.value.length; i++) {
      const file = fileList.value[i];
      if (file.status !== "finished") continue;
      
      const type = getFileType(file);
      
      // 处理视频文件
      if (type === "video") {
        if (file.url === FileTypes.VIDEO.defaultCover) {
          currentValue.push(file.name);
        } else {
          const result = {};
          result[props.fieldVideo] = file.name;
          result[props.fieldCover] = file.url;
          currentValue.push(result);
        }
      } else {
        // 处理其他文件
        currentValue.push(type === "pdf" ? file.name : file.url);
      }
    }

    // 将新值转换为数组进行比较
    const compareValue = Array.isArray(newValue) ? newValue : [newValue];

    // 长度不同，直接返回false
    if (currentValue.length !== compareValue.length) return false;

    // 逐项比较
    for (let i = 0; i < compareValue.length; i++) {
      const item = compareValue[i];
      const curr = currentValue[i];
      
      // 如果都是对象，比较对象的属性
      if (typeof item === "object" && typeof curr === "object") {
        if (item[props.fieldVideo] !== curr[props.fieldVideo] ||
            item[props.fieldCover] !== curr[props.fieldCover]) {
          return false;
        }
      } 
      // 否则直接比较值
      else if (item !== curr) {
        return false;
      }
    }
    
    return true;
  }

  // 如果值相等，不需要更新
  if (isValueEqual()) return;

  /**
   * 根据accept属性处理文件
   * @returns {Array} - 处理后的文件列表
   */
  function processFilesByAccept() {
    // 获取accept属性
    const acceptTypes = props.accept ? String(props.accept).split(",") : null;

    // 如果没有accept限制
    if (!acceptTypes) {
      // 将值转换为数组
      const items = Array.isArray(newValue) ? newValue : [newValue];
      
      // 分离视频和其他文件
      const videos = [];
      const others = [];
      
      for (let i = 0; i < items.length; i++) {
        const item = items[i];
        if ((typeof item === "object" && item[props.fieldVideo]) ||
            (typeof item === "string" && isVideo(item))) {
          videos.push(item);
        } else if (typeof item === "string" && !isVideo(item)) {
          others.push(item);
        }
      }

      // 合并处理结果
      return [
        ...handleVideoFiles(videos),
        ...handleImageAndPdf(others)
      ];
    }

    /**
     * 检查是否接受指定类型
     * @param {string} type - 文件类型
     * @returns {boolean} - 是否接受
     */
    function isAcceptedType(type) {
      for (let i = 0; i < acceptTypes.length; i++) {
        if (acceptTypes[i].includes(type)) {
          return true;
        }
      }
      return false;
    }
    
    // 根据accept类型处理文件
    if (isAcceptedType("video")) {
      return handleVideoFiles(newValue);
    }

    if (isAcceptedType("image") || isAcceptedType("pdf")) {
      return handleImageAndPdf(newValue);
    }

    return [];
  }

  // 设置文件列表
  fileList.value = processFilesByAccept();
}

/**
 * 处理文件预览
 * @param {Object} file - 文件对象
 */
function handlePreview(file) {
  const type = getFileType(file);
  
  // 触发预览事件（移到前面可以让父组件有机会拦截默认预览行为）
  emit('preview', { file });
  
  // 根据文件类型执行不同的预览操作
  if (type === "video" && file.name) {
    previewVideoUrl.value = file.name;
    showPreview.value = true;
  } else if (type === "pdf" && file.name) {
    window.open(file.name);
  } else if (type === "image") {
    previewImage(file.url);
  }
}

/**
 * 处理文件删除
 * @param {Object} file - 文件对象
 * @param {number} index - 文件索引
 * @param {Event} event - 事件对象
 */
function handleRemove(file, index, event) {
  // 阻止事件冒泡
  if (event) {
    event.stopPropagation();
    event.preventDefault();
  }
  
  // 触发删除事件（移到前面可以让父组件有机会拦截删除行为）
  emit('remove', { file, index });
  
  // 从列表中移除并更新值
  fileList.value.splice(index, 1);
  updateFileList();
}

/**
 * 处理文件下载
 * @param {Object} file - 文件对象
 * @param {Event} event - 事件对象
 */
function handleDownload(file, event) {
  // 阻止事件冒泡
  if (event) {
    event.stopPropagation();
    event.preventDefault();
  }
  
  // 触发下载事件（移到前面可以让父组件有机会拦截默认下载行为）
  emit('download', { file });
  
  const url = file.name || file.url;
  if (!url) return;
  
  // 创建下载链接
  const a = document.createElement('a');
  a.href = url;
  a.download = file.name || url.split('/').pop() || '下载文件';
  a.target = '_blank';
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
}

/**
 * 处理文件选择
 * @param {Event} event - 事件对象
 */
async function handleFileChange(event) {
  const files = event.target.files;
  if (!files || files.length === 0) return;
  
  console.log("文件选择触发：", files.length, "个文件");
  
  // 检查是否超过最大数量
  if (props.max > 0 && fileList.value.length + files.length > props.max) {
    message.warning(`最多只能上传${props.max}个文件`);
    return;
  }
  
  // 处理文件
  await handleFiles(files);
  
  // 清空input的值，允许重复选择相同文件
  event.target.value = '';
}

/**
 * 处理拖拽相关的事件
 * @param {DragEvent} event - 拖拽事件
 * @param {string} type - 事件类型 ('enter', 'leave', 'drop')
 */
function handleDrag(event, type) {
  event.preventDefault();
  event.stopPropagation();
  
  // 拖拽状态控制
  if (type === 'enter') {
    dragActive.value = true;
  } else if (type === 'leave') {
    dragActive.value = false;
  } else if (type === 'drop') {
    dragActive.value = false;
    
    // 如果组件禁用或没有文件，不处理
    if (props.disabled) return;
    
    const files = event.dataTransfer.files;
    if (!files || files.length === 0) return;
    
    // 检查是否超过最大数量
    if (props.max > 0 && fileList.value.length + files.length > props.max) {
      message.warning(`最多只能上传${props.max}个文件`);
      return;
    }
    
    // 处理所有文件
    handleFiles(files);
  }
}

/**
 * 处理文件列表
 * @param {FileList} files - 文件列表
 */
async function handleFiles(files) {
  for (let i = 0; i < files.length; i++) {
    const file = files[i];
    
    // 验证文件
    const isValid = await validateBeforeUpload(file);
    if (isValid !== false) {  // 只要不是明确返回false就继续上传
      // 上传文件
      await UploadHandler.uploadFile(file);
    }
  }
}

/**
 * 触发文件选择对话框
 */
function triggerFileInput() {
  if (props.disabled) return;
  console.log("触发文件选择器");
  if (inputFileRef.value) {
    inputFileRef.value.click();
  } else {
    console.error("文件输入引用未找到！");
  }
}

// 组件挂载时的处理
onMounted(() => {
  console.log("组件挂载完成");
  // 检查文件输入引用是否存在
  console.log("文件输入引用状态:", inputFileRef.value ? "已找到" : "未找到");
});

// 监听value变化
watch(
  () => props.value,
  (newValue, oldValue) => {
    // 如果值相等，不处理
    if (isEqual(newValue, oldValue)) return;
    
    // 保存旧值并初始化文件列表
    previousValue.value = newValue;
    initFileList();
  },
  { immediate: true }
);

// 暴露组件内部属性
defineExpose({
  isUploading,
  fileList
});

// 添加一个计算属性用于在模板中使用
const numWidth = computed(() => {
  return parseInt(String(props.itemWidth).replace(/[^0-9]/g, ''));
});
</script>

<template>
  <div 
    class="x-upload-container" 
    :data-instance-id="instanceId"
    @dragenter="(e) => handleDrag(e, 'enter')"
    @dragover.prevent
    @dragleave="(e) => handleDrag(e, 'leave')"
    @drop="(e) => handleDrag(e, 'drop')"
  >
    <!-- 隐藏的文件输入框 -->
    <input 
      ref="inputFileRef"
      type="file"
      class="hidden"
      :multiple="props.multiple"
      :accept="props.accept"
      @change="handleFileChange"
    />
    
    <!-- 文件列表 -->
    <div class="x-upload-file-list" :class="{ 'drag-active': dragActive }">
      <!-- 已上传的文件项 -->
      <div 
        v-for="(file, index) in fileList" 
        :key="file.id || index"
        class="x-upload-file-item"
        :style="{
          width: memoizedComputedStyles.fileWidth,
          height: memoizedComputedStyles.fileHeight
        }"
        @click="handlePreview(file)"
      >
        <!-- 文件预览 -->
        <div class="x-upload-file-preview">
          <!-- 图片预览 -->
          <img 
            v-if="file.url" 
            :src="file.url" 
            class="x-upload-image"
            alt="file preview"
          />
          
          <!-- 上传中状态 -->
          <div v-if="file.status === 'uploading'" class="x-upload-progress-mask">
            <div class="x-upload-progress">
              <div 
                class="x-upload-progress-info" 
                :style="{ 
                  fontSize: memoizedComputedStyles.progressFontSize, 
                  marginBottom: numWidth.value <= 50 ? '4px' : '8px' 
                }"
              >
                上传中 {{ file.percentage }}%
              </div>
              <div class="x-upload-progress-bar" :style="{ height: memoizedComputedStyles.progressBarHeight }">
                <div class="x-upload-progress-inner" :style="{ width: `${file.percentage}%` }"></div>
              </div>
            </div>
          </div>
          
          <!-- 重试中状态 -->
          <div v-if="file.status === 'retrying'" class="x-upload-progress-mask">
            <div class="x-upload-progress">
              <div 
                class="x-upload-progress-info"
                :style="{ 
                  fontSize: memoizedComputedStyles.progressFontSize, 
                  marginBottom: numWidth.value <= 50 ? '4px' : '8px' 
                }"
              >
                重试中 {{ retryingFiles[file.id]?.count || 0 }}/{{ props.maxRetries }}
              </div>
              <div class="x-upload-progress-bar" :style="{ height: memoizedComputedStyles.progressBarHeight }">
                <div class="x-upload-progress-inner" :style="{ width: `${file.percentage}%` }"></div>
              </div>
            </div>
          </div>
          
          <!-- 错误状态 -->
          <div v-if="file.status === 'error'" class="x-upload-error-mask">
            <div class="x-upload-error-icon" :style="{ fontSize: numWidth.value <= 50 ? '16px' : '24px' }">
              <svg viewBox="0 0 24 24" fill="currentColor" :style="{ width: numWidth.value <= 50 ? '16px' : '24px', height: numWidth.value <= 50 ? '16px' : '24px' }">
                <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/>
              </svg>
            </div>
            <div class="x-upload-error-text" :style="{ fontSize: memoizedComputedStyles.progressFontSize }">上传失败</div>
          </div>
          
          <!-- 悬浮操作按钮区域 -->
          <div v-if="file.status === 'finished'" class="x-upload-hover-actions">
            <!-- 外部自定义插槽 -->
            <slot 
              name="file-actions" 
              :file="file" 
              :index="index"
              :handle-preview="() => handlePreview(file)"
              :handle-remove="(e) => handleRemove(file, index, e)"
              :handle-download="(e) => handleDownload(file, e)"
            >
              <!-- 默认按钮区域 -->
              <div class="x-upload-action-buttons">
                <!-- 查看按钮 -->
                <button
                  class="x-upload-action-button x-upload-preview-button"
                  type="button"
                  title="查看"
                  :style="{ width: memoizedComputedStyles.actionButtonSize, height: memoizedComputedStyles.actionButtonSize }"
                  @click.stop="handlePreview(file)"
                >
                  <svg viewBox="0 0 24 24" fill="currentColor" :style="{ width: memoizedComputedStyles.actionIconSize, height: memoizedComputedStyles.actionIconSize }">
                    <path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"/>
                  </svg>
                </button>
                
                <!-- 下载按钮 -->
                <button
                  v-if="props.showDownload"
                  class="x-upload-action-button x-upload-download-button"
                  type="button"
                  title="下载"
                  :style="{ width: memoizedComputedStyles.actionButtonSize, height: memoizedComputedStyles.actionButtonSize }"
                  @click.stop="handleDownload(file, $event)"
                >
                  <svg viewBox="0 0 24 24" fill="currentColor" :style="{ width: memoizedComputedStyles.actionIconSize, height: memoizedComputedStyles.actionIconSize }">
                    <path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/>
                  </svg>
                </button>
                
                <!-- 删除按钮 -->
                <button
                  v-if="props.showDelete && !props.disabled"
                  class="x-upload-action-button x-upload-delete-button"
                  type="button"
                  title="删除"
                  :style="{ width: memoizedComputedStyles.actionButtonSize, height: memoizedComputedStyles.actionButtonSize }"
                  @click.stop="handleRemove(file, index, $event)"
                >
                  <svg viewBox="0 0 24 24" fill="currentColor" :style="{ width: memoizedComputedStyles.actionIconSize, height: memoizedComputedStyles.actionIconSize }">
                    <path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/>
                  </svg>
                </button>
              </div>
            </slot>
          </div>
        </div>
      </div>
      
      <!-- 上传按钮 -->
      <div 
        v-if="props.max <= 0 || fileList.length < props.max"
        class="x-upload-trigger"
        :class="{ 'x-upload-disabled': props.disabled }"
        :style="memoizedComputedStyles.uploadButton"
        @click="!props.disabled && triggerFileInput()"
      >
        <slot>
          <div class="x-upload-trigger-content">
            <span class="x-upload-plus-icon" :style="{ fontSize: memoizedComputedStyles.plusIconSize }">+</span>
          </div>
        </slot>
      </div>
    </div>
  </div>
  
  <!-- 视频预览层 -->
  <transition name="fade">
    <div
      v-if="showPreview"
      class="x-video-preview-overlay"
    >
      <div class="x-video-preview-header">
        <button
          class="x-video-preview-close"
          @click="showPreview = false"
          type="button"
        >
          <svg viewBox="0 0 24 24" fill="currentColor">
            <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
          </svg>
        </button>
      </div>

      <div class="x-video-preview-content">
        <video
          class="x-video-player"
          controls
        >
          <source :src="previewVideoUrl" type="video/mp4">
          您的浏览器不支持视频播放
        </video>
      </div>
    </div>
  </transition>
</template>

<style scoped>
/* 基础容器样式 */
.x-upload-container {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
}

.x-upload-file-list {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  width: 100%;
  padding: 8px 0;
  border-radius: 4px;
  transition: all 0.3s;
}

.x-upload-file-list.drag-active {
  background-color: rgba(45, 140, 240, 0.05);
  border: 1px dashed #462aa0;
}

/* 文件项样式 */
.x-upload-file-item {
  position: relative;
  display: flex;
  flex-direction: column;
  border-radius: 4px;
  overflow: hidden;
  border: 1px solid #e5e6eb;
  background-color: #fafafa;
  transition: all 0.3s;
  cursor: pointer;
}

.x-upload-file-preview {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  overflow: hidden;
  height: 100%;
  width: 100%;
}

.x-upload-image {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* 统一遮罩层样式 */
.x-upload-progress-mask, 
.x-upload-error-mask,
.x-upload-hover-actions {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background-color: rgba(0, 0, 0, 0.5);
  color: white;
  text-align: center;
  padding: 4px;
  box-sizing: border-box;
}

/* 悬浮操作区 */
.x-upload-hover-actions {
  opacity: 0;
  transition: opacity 0.2s;
}

.x-upload-file-item:hover .x-upload-hover-actions {
  opacity: 1;
}

/* 按钮组 */
.x-upload-action-buttons {
  display: flex;
  justify-content: center;
  gap: 4px;
  flex-wrap: wrap;
  max-width: 100%;
  padding: 2px;
}

/* 响应式按钮排列 */
@media (max-width: 768px) {
  .x-upload-file-item[style*="width: 40px"] .x-upload-action-buttons,
  .x-upload-file-item[style*="width:40px"] .x-upload-action-buttons,
  .x-upload-file-item[style*="width: 30px"] .x-upload-action-buttons,
  .x-upload-file-item[style*="width:30px"] .x-upload-action-buttons,
  .x-upload-file-item[style*="width: 20px"] .x-upload-action-buttons,
  .x-upload-file-item[style*="width:20px"] .x-upload-action-buttons {
    flex-direction: column;
    gap: 2px;
  }
  
  .x-upload-action-buttons {
    gap: 2px;
  }
}

/* 操作按钮 */
.x-upload-action-button {
  border-radius: 50%;
  background-color: white;
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.2s;
  color: #606266;
  padding: 0;
  min-width: 16px;
  min-height: 16px;
}



.x-upload-preview-button:hover {
  background-color: #e6f7ff;
  color: #1890ff;
}

.x-upload-download-button:hover {
  background-color: #e6fffb;
  color: #13c2c2;
}

.x-upload-delete-button:hover {
  background-color: #fff1f0;
  color: #f5222d;
}

/* 进度条相关 */
.x-upload-progress {
  width: 80%;
  text-align: center;
  max-width: 100%;
}

.x-upload-progress-info {
  margin-bottom: 8px;
  word-break: break-word;
  white-space: normal;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.x-upload-progress-bar {
  width: 100%;
  background-color: rgba(255, 255, 255, 0.3);
  border-radius: 3px;
  overflow: hidden;
}

.x-upload-progress-inner {
  height: 100%;
  background-color: #18a058;
  transition: width 0.2s linear;
}

/* 错误状态 */
.x-upload-error-icon {
  color: #f56c6c;
  margin-bottom: 4px;
  line-height: 1;
}

.x-upload-error-text {
  word-break: break-word;
  white-space: normal;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 上传触发区域 */
.x-upload-trigger {
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  background-color: #fafafa;
  cursor: pointer;
  transition: all 0.2s;
  min-width: 30px;
  min-height: 30px;
  position: relative;
}

.x-upload-trigger:hover:not(.x-upload-disabled) {
  border-color: #462aa0 !important;
  color: #462aa0;
}

.x-upload-disabled {
  cursor: not-allowed;
  color: #c0c4cc;
  background-color: #f5f7fa;
  border-color: #e4e7ed;
}

.x-upload-trigger-content {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}

.x-upload-plus-icon {
  font-weight: bold;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}

.hidden {
  display: none;
}

/* 视频预览 */
.x-video-preview-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 9999;
  display: flex;
  flex-direction: column;
  background-color: rgba(0, 0, 0, 0.85);
  backdrop-filter: blur(5px);
}

.x-video-preview-header {
  display: flex;
  justify-content: flex-end;
  padding: 16px;
}

.x-video-preview-close {
  color: white;
  background: none;
  border: none;
  cursor: pointer;
  width: 24px;
  height: 24px;
}

.x-video-preview-close svg {
  width: 24px;
  height: 24px;
  transition: transform 0.3s;
}

.x-video-preview-close:hover svg {
  transform: rotate(90deg);
}

.x-video-preview-content {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 24px 24px;
}

.x-video-player {
  max-width: 100%;
  max-height: 80vh;
  background-color: black;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
  border-radius: 4px;
  aspect-ratio: 16 / 9;
}

/* 动画 */
.fade-enter-active,
.fade-leave-active {
  transition: all 0.3s;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
  transform: scale(0.95);
}
</style>
