// composables/useMultiFileUpload.js
import { ref, reactive } from 'vue';
import SparkMD5 from 'spark-md5';

const CHUNK_SIZE = 2 * 1024 * 1024; // 2MB
const FILE_CONCURRENT_LIMIT = 3; // 同时上传几个文件（宏观并发）
const CHUNK_CONCURRENT_LIMIT = 3; // 每个文件内部同时传几片（微观并发）

export function useMultiFileUpload() {
  // 存储所有文件的上传任务状态
  // key: file.uid (element-plus生成的唯一ID), value: taskObject
  const uploadTasks = reactive({}); 

  const calculateFileMD5 = (file) => {
    return new Promise((resolve, reject) => {
      const spark = new SparkMD5.ArrayBuffer();
      const fileReader = new FileReader();
      let currentChunk = 0;
      const chunks = Math.ceil(file.size / CHUNK_SIZE);

      fileReader.onload = (e) => {
        spark.append(e.target.result);
        currentChunk++;
        if (currentChunk < chunks) {
          loadNext();
        } else {
          resolve(spark.end());
        }
      };
      fileReader.onerror = () => reject(new Error('文件读取失败'));

      const loadNext = () => {
        const start = currentChunk * CHUNK_SIZE;
        const end = Math.min(start + CHUNK_SIZE, file.size);
        fileReader.readAsArrayBuffer(file.slice(start, end));
      };
      loadNext();
    });
  };

  const uploadChunkWithRetry = async (formData, chunkIndex, maxRetries = 3) => {
    let retryCount = 0;
    while (retryCount < maxRetries) {
      try {
        const response = await fetch('/upload/chunk', { method: 'POST', body: formData });
        if (!response.ok) throw new Error(`HTTP ${response.status}`);
        return await response.json();
      } catch (error) {
        retryCount++;
        if (retryCount === maxRetries) throw error;
        await new Promise((r) => setTimeout(r, 1000 * retryCount));
      }
    }
  };

  // 单个文件的上传主逻辑
  const processFile = async (rawFile, updateCallback) => {
    const uid = rawFile.uid;
    
    // 初始化任务状态
    uploadTasks[uid] = {
      status: 'checking', // checking, uploading, merging, success, error, paused
      progress: 0,
      message: '正在检查文件...',
      cancelFlag: false,
      pauseFlag: false
    };

    const updateState = (status, progress, message) => {
      if (uploadTasks[uid]) {
        uploadTasks[uid].status = status;
        uploadTasks[uid].progress = progress;
        uploadTasks[uid].message = message;
      }
      // 通知组件更新 UI
      if (updateCallback) updateCallback(uid, status, progress, message);
    };

    try {
      // 1. 计算 MD5
      const fileMd5 = await calculateFileMD5(rawFile);
      
      // 2. 检查秒传/断点
      updateState('checking', 5, '正在检查服务器记录...');
      const checkResult = await fetch(
        `/upload/check?fileName=${encodeURIComponent(rawFile.name)}&fileMd5=${fileMd5}&fileSize=${rawFile.size}`
      ).then(res => res.json());

      if (checkResult.uploaded) {
        updateState('success', 100, '秒传成功');
        return { success: true, message: '秒传' };
      }

      const uploadedChunks = new Set(checkResult.uploadedChunks || []);
      const totalChunks = Math.ceil(rawFile.size / CHUNK_SIZE);
      const initialProgress = Math.round((uploadedChunks.size / totalChunks) * 100);
      
      updateState('uploading', initialProgress, `准备上传 (已存在 ${uploadedChunks.size}/${totalChunks} 片)`);

      // 3. 准备分片队列
      const pendingChunks = [];
      for (let i = 0; i < totalChunks; i++) {
        if (!uploadedChunks.has(i)) pendingChunks.push(i);
      }

      // 4. 并发上传分片
      const runChunkTask = async () => {
        while (pendingChunks.length > 0 && !uploadTasks[uid].cancelFlag) {
          // 处理暂停
          while (uploadTasks[uid].pauseFlag && !uploadTasks[uid].cancelFlag) {
            await new Promise(r => setTimeout(r, 500));
          }
          if (uploadTasks[uid].cancelFlag) break;

          const chunkIndex = pendingChunks.shift();
          const start = chunkIndex * CHUNK_SIZE;
          const end = Math.min(start + CHUNK_SIZE, rawFile.size);
          const chunk = rawFile.slice(start, end);

          const formData = new FormData();
          formData.append('file', chunk);
          formData.append('chunkIndex', chunkIndex);
          formData.append('totalChunks', totalChunks);
          formData.append('fileName', rawFile.name);
          formData.append('fileMd5', fileMd5);

          await uploadChunkWithRetry(formData, chunkIndex);

          // 更新进度
          const currentUploaded = totalChunks - pendingChunks.length + uploadedChunks.size;
          const percent = Math.min(99, Math.round((currentUploaded / totalChunks) * 100));
          updateState('uploading', percent, `上传中 ${percent}%`);
        }
      };

      // 启动微观并发
      const workers = Array.from({ length: Math.min(CHUNK_CONCURRENT_LIMIT, pendingChunks.length) }, () => runChunkTask());
      await Promise.all(workers);

      if (uploadTasks[uid].cancelFlag) {
        updateState('error', 0, '用户取消');
        return { success: false, message: 'Cancelled' };
      }

      // 5. 合并
      updateState('merging', 99, '正在合并文件...');
      await fetch('/upload/merge', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ fileName: rawFile.name, fileMd5: fileMd5, totalChunks })
      }).then(res => res.json());

      updateState('success', 100, '上传完成');
      return { success: true, message: 'Success' };

    } catch (error) {
      if (!uploadTasks[uid].cancelFlag) {
        updateState('error', 0, error.message || '上传失败');
      }
      return { success: false, error };
    }
  };

  // 对外暴露的方法
  const startUpload = (rawFile, updateCallback) => {
    if (!rawFile) return;
    // 如果该文件已经在上传，先忽略或提示
    if (uploadTasks[rawFile.uid]?.status === 'uploading') return;
    
    processFile(rawFile, updateCallback);
  };

  const pauseFile = (uid) => {
    if (uploadTasks[uid]) uploadTasks[uid].pauseFlag = true;
  };

  const resumeFile = (uid) => {
    if (uploadTasks[uid]) uploadTasks[uid].pauseFlag = false;
  };

  const cancelFile = (uid) => {
    if (uploadTasks[uid]) {
      uploadTasks[uid].cancelFlag = true;
      uploadTasks[uid].pauseFlag = false;
      uploadTasks[uid].status = 'error';
      uploadTasks[uid].message = '已取消';
    }
  };

  const getTaskStatus = (uid) => uploadTasks[uid] || null;

  return {
    startUpload,
    pauseFile,
    resumeFile,
    cancelFile,
    getTaskStatus,
    uploadTasks // 响应式对象，可直接在模板中使用
  };
}