<template>
  <div class="webuploader-container">
    <el-upload
      :action="uploadUrl"
      :before-upload="handleBeforeUpload"
      :on-success="handleSuccess"
      :on-error="handleError"
      :on-progress="handleProgress"
      :show-file-list="false"
      :headers="uploadHeaders"
      :data="uploadData"
      :accept="props.accept"
      :auto-upload="true"
      class="upload-box"
    >
      <!-- 自定义上传按钮 -->
      <div class="btntext upname" style="width: 28px; height: 24px">
        <img :src="props.imgSrc" alt="upload icon" class="custom-icon" />
      </div>
    </el-upload>
  </div>
</template>

<script setup>
import { ElMessage } from 'element-plus'
import SparkMD5 from 'spark-md5'
import { request } from '@/utils/request'

const props = defineProps({
  projectId: Number,
  solverType: String,
  accept: String,
  upId: String,
  name: String,
  namelist: Array,
  gfname: String,
  imgSrc: String,
})
const emit = defineEmits([
  'upload-success',
  'update-fileName',
  'update-percentage',
  'upload-status',
])

let fileMd5 = ref('')
let fileName = ref('')
let uuid = ref(generateUUID())

const uploadUrl = import.meta.env.VITE_BASE_URL + '/TransServlet'

const uploadHeaders = {
  Content: 'multipart',
  Type: 'form-data',
}

const uploadData = computed(() => ({
  transCode: 'B00028',
  channelNo: 'service',
  clientToken: 'e47b87eec69545559d1e81e56626da68',
  userId: '5f06c8bc77234f969d13e160b54c27e3',
  fileName: fileName.value,
  bfid: uuid.value,
}))

function generateUUID() {
  return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
    const r = (Math.random() * 16) | 0
    const v = c === 'x' ? r : (r & 0x3) | 0x8
    return v.toString(16)
  })
}

async function handleBeforeUpload(rawFile) {
  fileName.value = rawFile.name
  emit('update-fileName', fileName.value)

  const ext = fileName.value.split('.').pop().toLowerCase()
  const acceptList = props.accept
    .split(',')
    .map((e) => e.trim().replace(/^\./, '').toLowerCase())
  if (!acceptList.includes(ext)) {
    ElMessage.error(`只支持 ${props.accept} 格式文件!`)
    return false
  }

  fileMd5.value = await calculateMD5(rawFile)
  uuid.value = generateUUID()
  emit('upload-status', '上传中')
  return true
}

function handleSuccess(response, file) {
  if (response.returnCode !== '000000000') {
    ElMessage.error(response.returnMsg || '上传失败')
    emit('upload-status', '上传失败')
    return
  }

  emit('upload-success', {
    bfid: response.bfid,
    fname: file.name,
  })
  emit('upload-status', '上传成功')

  uuid.value = generateUUID()
}

function handleError() {
  emit('upload-status', '上传失败')
  uuid.value = generateUUID()
}

function handleProgress(event, file, fileList) {
  const percentage = Math.floor(event.percent)
  emit('update-percentage', percentage)
}

function calculateMD5(file) {
  return new Promise((resolve, reject) => {
    const chunkSize = 2097152 // 2MB
    const chunks = Math.ceil(file.size / chunkSize)
    let currentChunk = 0
    const spark = new SparkMD5.ArrayBuffer()
    const fileReader = new FileReader()

    fileReader.onload = function (e) {
      spark.append(e.target.result)
      currentChunk++
      if (currentChunk < chunks) {
        loadNext()
      } else {
        resolve(spark.end())
      }
    }

    fileReader.onerror = function () {
      reject(new Error('文件读取失败'))
    }

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

    loadNext()
  })
}
</script>

<style scoped>
.webuploader-container {
  position: relative;
}
.upload-box {
  display: inline-block;
}
.custom-icon {
  width: 100%;
  height: auto;
  display: block;
  cursor: pointer;
}
</style>
