<template>
  <div class="upload-component">
    <el-upload
      ref="uploadRef"
      v-model:file-list="uploadingFiles"
      :action="uploadUrl"
      :multiple="multiple"
      :limit="limit"
      :show-file-list="false"
      :headers="requestHeaders"
      :data="params"
      :before-upload="handleBeforeUpload"
      :on-progress="handleProgress"
      :on-success="handleSuccess"
      :on-exceed="handleExceed"
      :on-error="handleError"
      :on-change="handleFileChange"
      :accept="allowedFileTypes"
    >
      <slot />
    </el-upload>
    <popup
      v-if="showProgress"
      v-model="isProgressVisible"
      title="上传进度"
      width="500px"
      :close-on-click-modal="false"
      :modal="false"
      :show-footer="false"
      :align-center="false"
      @close="handleDialogClose"
    >
      <div class="py-1 flex flex-col gap-4">
        <div v-for="(file, index) in uploadingFiles" :key="file.uid || index">
          <div class="text-base font-medium">{{ file.name }}</div>
          <div class="w-full mt-1 flex items-center">
            <el-progress class="flex-1" :percentage="file.percentage || 0" />
            <div
              class="ml-1 flex items-center cursor-pointer text-danger"
              title="取消上传"
              @click.stop="handleCancel(file)"
              v-if="file.status === 'uploading'"
            >
              <el-icon :size="16"><CircleCloseFilled /></el-icon>
            </div>
            <div class="ml-1 flex items-center cursor-pointer text-success" title="上传成功" v-else>
              <el-icon :size="16"><SuccessFilled /></el-icon>
            </div>
          </div>
        </div>
      </div>
    </popup>
  </div>
</template>

<script setup lang="ts">
import { useUserStore } from '@/stores/user'
import type { UploadFile as ElUploadFile } from 'element-plus'
import { CircleCloseFilled, SuccessFilled } from '@element-plus/icons-vue'
import settings from '@/settings'

// 类型定义
interface UploadResponse {
  msg?: string
  status: 'success' | 'error' | 'cancel'
  [key: string]: any
}
// 组件属性
const props = withDefaults(
  defineProps<{
    // 上传文件类型 (image/video/默认*)
    type?: string
    // 是否支持多选
    multiple?: boolean
    // 最大文件数量限制
    limit?: number
    // 上传时的额外参数
    params?: Record<string, any>
    // 是否显示上传进度对话框
    showProgress?: boolean
    // 自定义上传地址
    customUrl?: string
    // 显示进度对话框的文件大小阈值（单位：字节）
    progressSizeThreshold?: number
  }>(),
  {
    type: '',
    multiple: true,
    limit: 10,
    params: () => ({}),
    showProgress: false,
    progressSizeThreshold: 3 * 1024 * 1024
  }
)
// 组件事件
const emit = defineEmits<{
  // 上传前校验事件
  (e: 'beforeUpload', file: File): void
  // 文件状态变化事件
  (e: 'change', file: ElUploadFile): void
  // 上传失败事件
  (e: 'error', file: ElUploadFile): void
  // 上传成功事件
  (e: 'success', response: UploadResponse): void
  // 所有文件上传完成事件
  (e: 'allSuccess', results: UploadResponse | UploadResponse[]): void
  // 上传进度更新事件
  (e: 'progress', file: ElUploadFile, event: any): void
}>()

// 状态管理
const userStore = useUserStore()
const uploadRef = shallowRef<InstanceType<typeof import('element-plus').ElUpload>>()
// 响应式状态
const isProgressVisible = ref(false)
const uploadingFiles = ref<ElUploadFile[]>([])
// 非响应式状态
let completedUploadCount = 0
let progressTimer: ReturnType<typeof setTimeout> | null = null
let uploadResults: UploadResponse[] = []

// 计算属性
const uploadUrl = computed(() => {
  return props.customUrl || `${useRuntimeConfig().public.VITE_API_BASE_URL || ''}${settings.urlPrefix}/upload/upload`
})
const requestHeaders = computed(() => {
  return {
    token: userStore.token
  }
})
const allowedFileTypes = computed(() => {
  switch (props.type) {
    case 'image':
      return settings.imageType.join(',')
    case 'video':
      return settings.videoType.join(',')
    default:
      return '*'
  }
})

// 重置上传状态
const resetUploadState = () => {
  if (progressTimer) {
    clearTimeout(progressTimer)
    progressTimer = null
  }
  completedUploadCount = 0
  uploadingFiles.value = []
  uploadResults = []
  isProgressVisible.value = false
}
// 处理上传完成后的逻辑
const handleUploadComplete = (shouldCloseDialog = true) => {
  if (shouldCloseDialog) {
    isProgressVisible.value = false
  }
  progressTimer = setTimeout(() => {
    if (props.multiple) {
      emit('allSuccess', uploadResults)
    } else {
      emit('allSuccess', uploadResults[0] || { status: 'error', msg: '上传失败' })
    }
    resetUploadState()
  }, 300)
}
// 文件状态变化事件
const handleFileChange = (file: ElUploadFile, fileList: ElUploadFile[]) => {
  if (fileList.length > uploadResults.length) {
    const newLength = fileList.length
    for (let i = uploadResults.length; i < newLength; i++) {
      uploadResults.push({
        msg: '上传失败',
        status: 'error'
      })
    }
  }
}
// 上传前校验
const handleBeforeUpload = (file: File) => {
  emit('beforeUpload', file )
}
// 上传进度更新事件
const handleProgress = (event: any, file: ElUploadFile) => {
  if (props.showProgress && (!file.size || file.size > props.progressSizeThreshold) && !isProgressVisible.value) {
    isProgressVisible.value = true
  }
  emit('progress', file, event)
}
// 上传成功处理
const handleSuccess = (response: UploadResponse, file: ElUploadFile) => {
  completedUploadCount++
  emit('change', file)
  const index = uploadingFiles.value.findIndex((item) => item.uid === file.uid)
  if (index !== -1 && index < uploadResults.length) {
    uploadResults[index] = {
      ...response,
      status: 'success'
    }
  }
  if (response.code === 1) {
    emit('success', response)
  } else if (response.code === 0 && response.msg) {
    ElMessage.error(response.msg)
  }
  if (completedUploadCount === uploadingFiles.value.length) {
    handleUploadComplete(response.code === 1)
  }
}
// 上传失败处理
const handleError = (error: Error, file: ElUploadFile) => {
  completedUploadCount++
  emit('change', file)
  emit('error', file)
  ElMessage.error(`${file.name} 文件上传失败`)
  const errorResponse: UploadResponse = {
    msg: '上传失败',
    status: 'error'
  }
  const index = uploadingFiles.value.findIndex((item) => item.uid === file.uid)
  if (index !== -1 && index < uploadResults.length) {
    uploadResults[index] = errorResponse
  }
  uploadRef.value?.abort(file)
  if (completedUploadCount === uploadingFiles.value.length) {
    handleUploadComplete()
  }
}
// 取消文件上传
const handleCancel = (file: ElUploadFile) => {
  if (file.status === 'uploading') {
    uploadRef.value?.abort(file)
    const index = uploadingFiles.value.findIndex((item) => item.uid === file.uid)
    if (index !== -1 && index < uploadResults.length) {
      uploadResults[index] = {
        msg: '上传取消',
        status: 'cancel'
      }
      uploadingFiles.value.splice(index, 1)
    }
    checkRemainingFiles()
  }
}
// 检查剩余文件状态
const checkRemainingFiles = () => {
  if (uploadingFiles.value.length === 0) {
    isProgressVisible.value = false
    if (props.multiple) {
      emit('allSuccess', uploadResults)
    } else {
      emit('allSuccess', uploadResults[0] || { status: 'error', msg: '上传失败' })
    }
    resetUploadState()
    return
  }
  const allCompleted = uploadingFiles.value.every((file) => file.status === 'success' || file.status === 'fail')
  if (allCompleted) {
    handleUploadComplete()
  }
}
// 超出文件数量限制
const handleExceed = () => {
  ElMessage.error(`超出上传上限 ${props.limit} 个文件，请重新上传`)
}
// 关闭进度对话框
const handleDialogClose = () => {
  isProgressVisible.value = false
  const filesCopy = [...uploadingFiles.value]
  filesCopy.forEach((file) => {
    if (file.status === 'uploading') {
      uploadRef.value?.abort(file)
      const index = uploadingFiles.value.findIndex((item) => item.uid === file.uid)
      if (index !== -1 && index < uploadResults.length) {
        uploadResults[index] = {
          msg: '上传取消',
          status: 'cancel'
        }
      }
    }
  })
  if (props.multiple) {
    emit('allSuccess', uploadResults)
  } else {
    emit('allSuccess', uploadResults[0] || { status: 'error', msg: '上传失败' })
  }
  resetUploadState()
}
</script>
