<script setup>
/**
 * 上传图片，并返回id，多个以,号分割
 */
import { computed, defineExpose, nextTick, onMounted, ref, watch } from 'vue';

import { MdiPlus } from '@vben/icons';

import { ElMessage, genFileId } from 'element-plus';

import { addAttachmentApi, addImageApi } from '#/api/file';

const props = defineProps({
  // v-model 默认绑定的值 (fileList)
  modelValue: {
    type: Array,
    default: () => [],
  },
  // v-model:fileIds 绑定的文件ID数组
  fileIds: {
    type: Array,
    default: () => [],
  },
  limit: {
    type: Number,
    default: 1,
  },
  attmodel: {
    type: String,
    required: true,
  },
  // 支持自定义路径
  attpath: {
    type: String,
    default: '',
  },
  attId: {
    type: String,
    default: '',
  },
  message: {
    type: String,
    default: '',
  },
  tips: {
    type: String,
    default: '',
  },
  listType: {
    type: String,
    default: 'text',
  },
  // 新增accept属性
  accept: {
    type: String,
    default: '',
  },
});

const emits = defineEmits([
  'update:modelValue',
  'update:fileIds',
  'update:fileID',
]);

const upload = ref(null);
const fileList = ref([]);
const fileIdsInternal = ref([]); // 上传后返回的id集合

// 计算实际使用的路径
const actualAttpath = computed(() => {
  return props.attpath || `/${props.attmodel}/`;
});

// 内部状态标记，防止循环更新
const isInternalUpdate = ref(false);

// 安全的数组比较函数
const arraysEqual = (a, b) => {
  if (!a && !b) return true;
  if (!a || !b) return false;
  if (a.length !== b.length) return false;
  return JSON.stringify(a) === JSON.stringify(b);
};

// 监听外部modelValue变化
watch(
  () => props.modelValue,
  async (newVal) => {
    if (isInternalUpdate.value) return;
    if (!arraysEqual(newVal, fileList.value)) {
      isInternalUpdate.value = true;
      fileList.value = newVal ? [...newVal] : [];
      await nextTick();
      isInternalUpdate.value = false;
    }
  },
  { deep: true, immediate: true },
);

// 监听外部fileIds变化
watch(
  () => props.fileIds,
  async (newVal) => {
    if (isInternalUpdate.value) return;
    if (!arraysEqual(newVal, fileIdsInternal.value)) {
      isInternalUpdate.value = true;
      fileIdsInternal.value = newVal ? [...newVal] : [];
      await nextTick();
      isInternalUpdate.value = false;
    }
  },
  { deep: true, immediate: true },
);

// 监听内部fileList变化，同步到外部
watch(
  fileList,
  async (newVal) => {
    if (isInternalUpdate.value) return;
    if (!arraysEqual(newVal, props.modelValue)) {
      isInternalUpdate.value = true;
      emits('update:modelValue', [...newVal]);
      await nextTick();
      isInternalUpdate.value = false;
    }
  },
  { deep: true },
);

// 监听内部fileIds变化，同步到外部
watch(
  fileIdsInternal,
  async (newVal) => {
    if (isInternalUpdate.value) return;
    if (!arraysEqual(newVal, props.fileIds)) {
      isInternalUpdate.value = true;
      emits('update:fileIds', [...newVal]);
      // 兼容原有的字符串格式
      const idStr = newVal
        .map((item) => (typeof item === 'object' ? item.id : item))
        .join(',');
      emits('update:fileID', idStr);
      await nextTick();
      isInternalUpdate.value = false;
    }
  },
  { deep: true },
);

const handleRemove = async (uploadFile, _uploadFiles) => {
  isInternalUpdate.value = true;
  fileIdsInternal.value = fileIdsInternal.value.filter(
    (item) => item.uid !== uploadFile.uid,
  );
  // 更新 fileList，移除对应文件
  const removedFileIndex = fileList.value.findIndex(
    (f) => f.uid === uploadFile.uid,
  );
  if (removedFileIndex !== -1) {
    const removedF = fileList.value.splice(removedFileIndex, 1)[0];
    // 如果是本地创建的 blob URL，则释放它
    if (removedF && removedF.url && removedF.url.startsWith('blob:')) {
      URL.revokeObjectURL(removedF.url);
    }
  }

  const idStr = fileIdsInternal.value.map((item) => item.id).join(',');
  emits('update:fileID', idStr);
  await nextTick();
  isInternalUpdate.value = false;
};

// 超出文件数量限制处理
const handleExceed = (files) => {
  // 当limit=1时，替换现有文件而不是添加新文件
  if (props.limit === 1) {
    ElMessage.warning('只能上传一个文件，将替换当前文件');
    // 清理现有文件和blob URL
    fileList.value.forEach((file) => {
      if (file.url && file.url.startsWith('blob:')) {
        URL.revokeObjectURL(file.url);
      }
    });
    // 清空所有相关状态
    fileList.value = [];
    fileIdsInternal.value = [];
    emits('update:fileIds', []);
    emits('update:fileID', '');

    // 处理新文件
    const file = files[0];
    file.uid = genFileId();
    if (upload.value) {
      upload.value.clearFiles();
      upload.value.handleStart(file);
    }
    handleUploadFile({ file });
  } else {
    // 多文件上传时的原有逻辑
    ElMessage.warning(`最多只能上传${props.limit}个文件`);
  }
};

// 添加文件选择前的检查
const beforeUpload = (_file) => {
  // 当limit=1且已有文件时，先清理现有文件
  if (props.limit === 1 && fileList.value.length > 0) {
    // 清理现有文件的blob URL
    fileList.value.forEach((existingFile) => {
      if (existingFile.url && existingFile.url.startsWith('blob:')) {
        URL.revokeObjectURL(existingFile.url);
      }
    });
    // 清空状态
    fileList.value = [];
    fileIdsInternal.value = [];
    emits('update:fileIds', []);
    emits('update:fileID', '');
  }
  return true;
};

// 预览图片（功能已移除）
const handlePictureCardPreview = (_uploadFile) => {
  // 预览功能已移除，因为使用本地blob URL预览
};

// 判断文件是否为图片类型
const isImageFile = (file) => {
  // 通过文件类型判断
  if (file.type && file.type.startsWith('image/')) {
    return true;
  }

  // 通过文件扩展名判断（作为备用方案）
  const imageExtensions = [
    '.jpg',
    '.jpeg',
    '.png',
    '.gif',
    '.bmp',
    '.webp',
    '.svg',
    '.pdf',
  ];
  const fileName = file.name.toLowerCase();
  return imageExtensions.some((ext) => fileName.endsWith(ext));
};

// 自定义上传文件
const handleUploadFile = async (option) => {
  const { file } = option;
  const localPreviewUrl = URL.createObjectURL(file); // 生成本地预览URL

  // 更新fileList以进行即时预览
  const existingFileIndex = fileList.value.findIndex((f) => f.uid === file.uid);
  if (existingFileIndex === -1) {
    // 查找el-upload可能已添加的文件条目
    const newFileInList = fileList.value.find((f) => f.uid === file.uid);
    if (newFileInList) {
      newFileInList.url = localPreviewUrl;
      newFileInList.status = 'uploading';
      newFileInList.percentage = 0; // 初始化进度为0
    } else {
      // 防御性添加（通常不需要，因为el-upload会自动管理）
      const newFileItem = {
        name: file.name,
        url: localPreviewUrl,
        uid: file.uid,
        status: 'uploading',
        percentage: 0, // 初始化进度为0
        raw: file,
      };

      // 当limit=1时，严格替换现有文件
      if (props.limit === 1) {
        // 清理现有文件的blob URL
        fileList.value.forEach((existingFile) => {
          if (existingFile.url && existingFile.url.startsWith('blob:')) {
            URL.revokeObjectURL(existingFile.url);
          }
        });
        // 清空并替换为新文件
        fileList.value = [newFileItem];
        // 同时清空fileIds，上传成功后会重新添加
        fileIdsInternal.value = [];
      } else if (fileList.value.length < props.limit) {
        fileList.value.push(newFileItem);
      }
    }
  } else {
    // 更新现有文件的预览URL
    fileList.value[existingFileIndex].url = localPreviewUrl;
    fileList.value[existingFileIndex].status = 'uploading';
    fileList.value[existingFileIndex].name = file.name;
    fileList.value[existingFileIndex].percentage = 0; // 初始化进度为0
  }

  const formData = new FormData();
  formData.append('attmodel', props.attmodel);
  formData.append('attpath', actualAttpath.value);
  formData.append('file', file);

  try {
    // 根据文件类型选择不同的上传接口
    const isImage = isImageFile(file);
    const res = isImage
      ? await addImageApi(formData)
      : await addAttachmentApi(formData);

    if (res.data && res.data.Status === 0) {
      const fileId = res.data.Data;
      const serverUrl = res.data.OtherData;

      // 更新fileIdsInternal并直接发送事件
      const newFileEntry = {
        uid: file.uid,
        id: fileId,
        name: file.name,
        url: serverUrl || '',
      };

      // 当limit=1时，替换所有现有文件ID
      if (props.limit === 1) {
        fileIdsInternal.value = [newFileEntry];
      } else {
        fileIdsInternal.value.push(newFileEntry);
      }

      // 直接发送事件，确保父组件及时接收
      emits('update:fileIds', [...fileIdsInternal.value]);
      const idStr = fileIdsInternal.value.map((item) => item.id).join(',');
      emits('update:fileID', idStr);

      // 更新fileList状态和URL
      await nextTick();
      isInternalUpdate.value = true;
      const uploadedFileEntry = fileList.value.find((f) => f.uid === file.uid);
      if (uploadedFileEntry) {
        // 释放blob URL并使用服务器URL
        if (
          uploadedFileEntry.url &&
          uploadedFileEntry.url.startsWith('blob:')
        ) {
          URL.revokeObjectURL(uploadedFileEntry.url);
        }
        uploadedFileEntry.attId = fileId;
        uploadedFileEntry.status = 'success';
        uploadedFileEntry.percentage = 100; // 上传成功时设置进度为100
        uploadedFileEntry.url = serverUrl || '';
      }
      await nextTick();
      isInternalUpdate.value = false;
    } else {
      ElMessage.error(res.data?.Message || '上传失败');
      updateFileStatusAndCleanup(file.uid, 'fail', localPreviewUrl);
    }
  } catch (error) {
    console.error('上传错误:', error);
    ElMessage.error('上传失败，请重试');
    updateFileStatusAndCleanup(file.uid, 'fail', localPreviewUrl);
  }
};

// 更新文件状态并清理blob URL的辅助函数
const updateFileStatusAndCleanup = (uid, status, _blobUrl) => {
  const fileEntry = fileList.value.find((f) => f.uid === uid);
  if (fileEntry) {
    fileEntry.status = status;
    // 如果状态是失败，设置进度为0，成功则设置为100
    fileEntry.percentage = status === 'success' ? 100 : 0;
    if (fileEntry.url && fileEntry.url.startsWith('blob:')) {
      URL.revokeObjectURL(fileEntry.url);
    }
  }
};

// 根据 fileIds 初始化 fileList
const initializeFileList = async () => {
  if (props.fileIds && props.fileIds.length > 0) {
    isInternalUpdate.value = true;
    const newFileList = [];

    for (const fileIdObj of props.fileIds) {
      const attId = typeof fileIdObj === 'object' ? fileIdObj.id : fileIdObj;
      const uid = typeof fileIdObj === 'object' ? fileIdObj.uid : genFileId();
      if (!attId) continue;

      // 优先从外部传入的 modelValue 中查找对应的文件信息
      const modelFile = props.modelValue.find(
        (f) =>
          f.attId === attId ||
          (f.uid === uid && f.name) ||
          (typeof f.attId === 'string' && f.attId === attId),
      );

      let fileName = `File_${attId}`;
      let fileUrl = '';

      if (modelFile) {
        fileName = modelFile.name || fileName;
        fileUrl = modelFile.url || '';
      }

      newFileList.push({
        name: fileName,
        url: fileUrl,
        attId,
        uid,
        status: 'success', // 设置状态为成功
        percentage: 100, // 已存在的文件进度设置为100
      });
    }

    fileList.value = newFileList;
    await nextTick();
    isInternalUpdate.value = false;
  } else if (
    (!props.fileIds || props.fileIds.length === 0) &&
    props.modelValue.length === 0
  ) {
    // 清空状态
    isInternalUpdate.value = true;
    fileList.value = [];
    fileIdsInternal.value = [];
    emits('update:fileID', '');
    await nextTick();
    isInternalUpdate.value = false;
  }
};

onMounted(async () => {
  await initializeFileList();
});

// 当 attId prop 变化时处理单个文件ID
watch(
  () => props.attId,
  async (newAttId) => {
    if (
      newAttId &&
      typeof newAttId === 'string' &&
      props.fileIds.length === 0
    ) {
      const pseudoFileId = {
        id: newAttId,
        uid: genFileId(),
        name: `File_${newAttId}`,
        url: '',
        status: 'success', // 设置状态为成功
        percentage: 100, // 已存在的文件进度设置为100
      };
      isInternalUpdate.value = true;
      fileIdsInternal.value = [pseudoFileId];
      emits('update:fileIds', [pseudoFileId]);
      await nextTick();
      isInternalUpdate.value = false;
      await initializeFileList();
    }
  },
  { immediate: true },
);

// 监听 fileIds 变化，重新初始化文件列表
watch(() => props.fileIds, initializeFileList, { deep: true });

// 暴露 clearFiles 方法
defineExpose({
  clearFiles: () => {
    if (upload.value) {
      upload.value.clearFiles();
    }
  },
});
</script>

<template>
  <div class="upload-file-container">
    <ElUpload
      ref="upload"
      v-model:file-list="fileList"
      action="#"
      :http-request="handleUploadFile"
      :limit="limit"
      :multiple="limit > 1"
      :on-exceed="handleExceed"
      :on-preview="handlePictureCardPreview"
      :on-remove="handleRemove"
      :list-type="listType"
      :before-upload="beforeUpload"
      :accept="accept"
    >
      <slot name="trigger">
        <MdiPlus />
      </slot>
      <template #tip>
        <div v-if="tips || message" class="el-upload__tip">
          {{ tips || message }}
        </div>
      </template>
    </ElUpload>
  </div>
</template>

<style lang="scss" scoped>
.upload-file-container {
  :deep(.el-upload--picture-card) {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100px; /* 设置默认宽度 */
    height: 100px; /* 设置默认高度 */
  }

  :deep(.el-upload-list--picture-card .el-upload-list__item) {
    width: 100px; /* 设置默认宽度 */
    height: 100px; /* 设置默认高度 */
    margin: 0 8px 8px 0; /* 统一间距 */
  }
}
</style>
