<template>
  <div class="upload-container">
    <!-- 文件上传区域 -->
    <el-upload
      ref="upload"
      class="upload-area"
      drag
      action="#"
      :auto-upload="false"
      :show-file-list="false"
      :on-change="handleFileChange"
      :accept="accept"
      multiple
    >
      <i class="el-icon-upload"></i>
      <div class="el-upload__text">将文件拖到此处，或<em>点击上传</em></div>
      <div class="el-upload__tip" slot="tip">只能上传图片和视频文件，且不超过500M</div>
    </el-upload>

    <!-- 文件夹上传 -->
    <div class="folder-upload">
      <input
        type="file"
        ref="folderInput"
        @change="handleFolderSelect"
        style="display: none"
        webkitdirectory
        multiple
      />
      <el-button 
        type="primary" 
        plain 
        icon="el-icon-folder-opened"
        @click="triggerFolderSelect"
        style="margin-top: 10px;"
      >
        选择文件夹上传
      </el-button>
    </div>

    <div class="preview-list" v-if="fileList.length > 0">
      <div v-for="(file, index) in fileList"
           :key="index"
           class="preview-item">
        <div class="delete-btn" @click="handleDelete(index)">
          <i class="el-icon-delete"></i>
        </div>

        <div v-if="file.type.includes('image')" class="preview-content">
          <img v-if="file.status == 'success'" :src="file.url" :alt="file.name">
        </div>

        <div v-else-if="file.type.includes('video')" class="preview-content video-filename">
          <div v-if="file.status == 'success'" class="filename-info">
            <i class="el-icon-video-camera-solid" style="font-size: 20px; color: #409EFF; margin-bottom: 5px;"></i>
            <div class="filename-text">{{ file.name }}</div>
          </div>
        </div>

        <el-progress
          v-if="file.status === 'uploading' || file.status === 'waiting'"
          type="circle"
          :percentage="file.displayProgress"
          :width="80"
          class="progress"
          :format="percentFormat"
        ></el-progress>
        <div v-else-if="file.status === 'success'" class="upload-success">
          <i class="el-icon-check"></i>
        </div>

        <div v-else-if="file.status === 'error'" class="upload-error">
          <el-tooltip :content="file.errorMessage" placement="top">
            <i class="el-icon-close"></i>
          </el-tooltip>
        </div>

        <div class="file-name">{{ file.name }}</div>
      </div>
    </div>
  </div>
</template>

<script>
import axios from 'axios'

export default {
  name: 'FileUpload',

  props: {
    // 接受的文件类型
    accept: {
      type: String,
      default: 'image/*,video/*'
    },
    // 上传地址
    uploadUrl: {
      type: String,
      required: true
    },
    // 额外的上传参数
    extraData: {
      type: Object,
      default: () => ({})
    },
    // 自定义请求头
    headers: {
      type: Object,
      default: () => ({})
    }
  },

  data() {
    return {
      fileList: [],
      uploadQueue: [],
      successFiles: [], // 存储上传成功的文件信息
      isProcessing: false, // 是否有上传中的文件
    }
  },

  methods: {
    // 重置组件状态
    reset() {
      this.cancelAllUploads()
      this.fileList = []
      this.uploadQueue = []
      this.successFiles = []
    },

    // 处理文件变化
    handleFileChange(file) {
      this.addFileToQueue(file.raw)
    },

    // 触发文件夹选择
    triggerFolderSelect() {
      this.$refs.folderInput.click()
    },

    // 处理文件夹选择
    handleFolderSelect(event) {
      const files = event.target.files
      for (let i = 0; i < files.length; i++) {
        const file = files[i]
        // 检查文件类型
        if (file.type.includes('image') || file.type.includes('video')) {
          this.addFileToQueue(file)
        }
      }
      // 清空input，以便可以重复选择同一个文件夹
      event.target.value = ''
    },

    // 添加文件到队列
    addFileToQueue(rawFile) {
      const fileObj = {
        raw: rawFile,
        name: rawFile.name,
        type: rawFile.type,
        url: URL.createObjectURL(rawFile),
        status: 'waiting',
        progress: 0,
        displayProgress: 0,
        errorMessage: '',
        progressTimer: null,
        size: rawFile.size,
        path: rawFile.webkitRelativePath || rawFile.name // 保存文件路径
      }

      this.fileList.push(fileObj)
      this.uploadQueue.push(fileObj)

      this.processUploadQueue()

      // if (this.uploadQueue.length === 1) {
      //   this.processUploadQueue()
      // }
    },

    handleDelete(index) {
      const file = this.fileList[index]

      if (file.progressTimer) {
        clearInterval(file.progressTimer)
      }

      if (file.cancelToken) {
        file.cancelToken.cancel('用户取消上传')
      }

      URL.revokeObjectURL(file.url)
      this.fileList.splice(index, 1)

      // 如果是已经上传成功的文件，也从成功列表中移除
      const successIndex = this.successFiles.findIndex(f => f.url === file.url)
      if (successIndex > -1) {
        this.successFiles.splice(successIndex, 1)
        this.$emit('update:files', [...this.successFiles])
      }

      const queueIndex = this.uploadQueue.indexOf(file)
      if (queueIndex > -1) {
        this.uploadQueue.splice(queueIndex, 1)
      }
    },

    startProgressSimulation(file) {
      let simulatedProgress = 0
      const maxSimulatedProgress = 95

      file.progressTimer = setInterval(() => {
        if (simulatedProgress < maxSimulatedProgress) {
          const remainingProgress = maxSimulatedProgress - simulatedProgress
          const increment = Math.random() * (remainingProgress * 0.1)

          simulatedProgress += increment
          simulatedProgress = Math.min(simulatedProgress, maxSimulatedProgress)

          file.displayProgress = Math.floor(simulatedProgress)
        }
      }, 200 + Math.random() * 300)
    },

    async processUploadQueue() {
      while (this.uploadQueue.length > 0) {
        if (this.isProcessing) return
        this.isProcessing = true
        await this.processSingleFile(this.uploadQueue[0])
        this.uploadQueue.shift()
        this.isProcessing = false
      }

      // 所有文件上传完成后触发事件
      if (this.uploadQueue.length === 0) {
        this.$emit('upload-complete', this.successFiles)
      }
    },

    async processSingleFile(file){
      file.status = 'uploading'
      this.startProgressSimulation(file)

      try {
        const response = await this.uploadFile(file)

        if (file.progressTimer) {
          clearInterval(file.progressTimer)
        }

        // 校验业务状态码
        if (response.data.status !== 200) { // 假设1表示成功
          file.displayProgress = 100
          file.status = 'error'
          this.$emit('upload-error', {
            file: file,
            error: new Error(response.data.msg || '业务状态异常')
          })
          console.log("文件上传失败，返回信息：", response.data)
        }else{
          file.displayProgress = 100
          file.status = 'success'
          console.log("response: ", response)
          // 构建成功文件的信息对象
          const successFileInfo = {
            name: file.name,
            cdnUrl: response.data.result.data.cdnUrl,
            fileMd5: response.data.result.data.fileMd5,
            type: response.data.result.data.type,
            size: file.size
          }
          console.log("successFileInfo: ", successFileInfo)
          // 更新成功文件列表
          this.successFiles.push(successFileInfo)
          // 触发更新事件
          this.$emit('update:files', [...this.successFiles])
          this.$emit('upload-success', successFileInfo)

        }
      } catch (error) {
        if (file.progressTimer) {
          clearInterval(file.progressTimer)
        }

        if (!axios.isCancel(error)) {
          file.status = 'error'
          // file.errorMessage = error.response?.data?.message || '上传失败'
          this.$emit('upload-error', {
            file: file,
            error: error
          })
        }
      }
    },


    uploadFile(file) {
      return new Promise((resolve, reject) => {
        const formData = new FormData()
        formData.append('files', file.raw)

        // 添加额外的上传参数
        Object.entries(this.extraData).forEach(([key, value]) => {
          formData.append(key, value)
        })

        const CancelToken = axios.CancelToken
        file.cancelToken = CancelToken.source()

        axios.post(
          this.uploadUrl,
          formData,
          {
            headers: {
              'Content-Type': 'multipart/form-data',
              ...this.headers
            },
            cancelToken: file.cancelToken.token,
            onUploadProgress: (progressEvent) => {
              if (progressEvent.lengthComputable) {
                file.progress = Math.round(
                  (progressEvent.loaded * 100) / progressEvent.total
                )
              }
            }
          }
        )
        .then(resolve)
        .catch(reject)
      })
    },

    cancelAllUploads() {
      this.fileList.forEach(file => {
        if (file.progressTimer) {
          clearInterval(file.progressTimer)
        }
        if (file.status === 'uploading' && file.cancelToken) {
          file.cancelToken.cancel('批量取消上传')
        }
      })
    },
    percentFormat(percent){
      return percent == 0 ? '等待中': `${percent}%`

    },

    beforeDestroy() {
      this.cancelAllUploads()

      this.fileList.forEach(file => {
        if (file.url && file.url.startsWith('blob:')) {
          URL.revokeObjectURL(file.url)
        }
      })
    },

    // 格式化文件大小
    formatFileSize(bytes) {
      if (bytes === 0) return '0 B'
      const k = 1024
      const sizes = ['B', 'KB', 'MB', 'GB', 'TB']
      const i = Math.floor(Math.log(bytes) / Math.log(k))
      return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
    }
  },
}
</script>

<style scoped>
/* 样式代码保持不变 */
.upload-container {
  padding: 20px;
}

.preview-list {
  display: flex;
  flex-wrap: wrap;
  margin-top: 20px;
  gap: 20px;
}

.preview-item {
  position: relative;
  width: 200px;
  height: 200px;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.upload-area{
  position: relative;
  width: 200px;
  height: 200px;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.preview-content {
  width: 100%;
  height: 150px;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #f5f7fa;
}

.preview-content img,
.preview-content video {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.delete-btn {
  position: absolute;
  top: 5px;
  right: 5px;
  width: 24px;
  height: 24px;
  background-color: rgba(0, 0, 0, 0.5);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 1;
}

.delete-btn i {
  color: white;
  font-size: 14px;
}

.progress {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background-color: rgba(255, 255, 255, 0.9);
  border-radius: 50%;
  padding: 10px;
}

.upload-success {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  color: #67c23a;
  font-size: 30px;
}

.upload-error {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  color: #f56c6c;
  font-size: 30px;
  cursor: pointer;
}

upload-waiting {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  color: #f56c6c;
  font-size: 30px;
  cursor: pointer;
}

.file-name {
  margin-top: auto;
  padding: 8px;
  width: 100%;
  text-align: center;
  font-size: 12px;
  color: #606266;
  background-color: #f5f7fa;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 视频文件名样式 */
.video-filename {
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #f8f9fc;
  padding: 10px;
}

.filename-info {
  text-align: center;
  color: #606266;
  max-width: 100%;
}

.filename-text {
  font-size: 12px;
  color: #303133;
  word-break: break-all;
  line-height: 1.4;
  max-width: 120px;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
</style>
