// 定义文件上传任务类型
interface UploadTask<R, K> {
  myFlie: R
  resolve: (res: K) => void
  reject: (error: Error) => void
}
type UploadFile<R = any, K = any> = (myFlie: R) => Promise<K>

/**
 * 文件上传服务类（单例模式）,
 */
export class FileUploadService<R, K> {
  /** 当前上传的数量 */
  private currentUploads = 0
  /** 一次最多上传多少个，剩下的加入队列 */
  private concurrency = 5
  /** 上传队列 */
  private uploadTaskList: UploadTask<R, K>[] = []
  /** 上传的方法 */
  private uploadFile: UploadFile<R, K>

  /**
   * 私有构造函数
   */
  public constructor(_uploadFile: UploadFile, _concurrency?: number) {
    this.currentUploads = 0
    this.concurrency = _concurrency || 5 // 默认并发数为2，可以根据需要调整
    this.uploadTaskList = []
    this.uploadFile = _uploadFile
  }

  /**
   * 执行文件上传
   * @param filesToUpload - 要上传的文件对象数组
   * @param concurrency - 并发上传数，默认为构造函数中设置的并发数
   */
  public upload(filesToUpload: R[], concurrency: number = this.concurrency): Promise<PromiseSettledResult<Awaited<K>>[]> {
    return new Promise<PromiseSettledResult<Awaited<K>>[]>((resolve, reject) => {
      const uploadPromises = filesToUpload.map(file => this.addUploadTask(file))
      this.concurrency = concurrency // 更新并发数

      // 返回所有上传任务的 Promise
      Promise.allSettled(uploadPromises)
        .then((res) => {
          resolve(res) // 所有任务完成后调用总体解决函数
        })
        .catch((err) => {
          console.error('文件上传过程中出现错误:')
          reject(err) // 如果有任务失败，直接调用总体拒绝函数
        })
    })
  }

  /**
   * 添加上传任务到队列
   * @param file - 要上传的文件对象
   */
  private addUploadTask(myFlie: R): Promise<K> {
    return new Promise<K>((resolve, reject) => {
      if (this.currentUploads < this.concurrency) {
        // 如果当前上传数小于并发数，则直接上传
        this.currentUploads++
        this.uploadFile(myFlie)
          .then((res: K) => {
            this.currentUploads--
            resolve(res)
            this.processQueue()
          })
          .catch((error) => {
            this.currentUploads--
            console.error(`上传失败,文件：`, myFlie, '错误====', error)
            reject(error)
            this.processQueue()
          })
      }
      else {
        // 如果当前上传数达到并发数，则加入队列等待
        this.uploadTaskList.push({ myFlie, resolve, reject })
      }
    })
  }

  /**
   * 处理上传队列，依次执行上传任务
   */
  private processQueue(): void {
    if (this.uploadTaskList.length > 0) {
      const { myFlie, resolve, reject } = this.uploadTaskList.shift()!
      this.addUploadTask(myFlie)
        .then((res: K) => {
          resolve(res) // 在完成上传后，调用任务的 resolve
        })
        .catch((err) => {
          reject(err)
        })
    }
  }

  /**
   * 停止上传
   */
  public abort(): void {
    this.uploadTaskList = []
  }
}
