<template>
  <div class="upload-file">
    <el-upload
      ref="uploadRef"
      v-loading="loading"
      v-bind="$attrs"
      :file-list="fileList"
      drag
      :disabled="disabled"
      :multiple="limit > 1"
      :on-error="handleUploadError"
      :on-change="handleChange"
      :auto-upload="false"
      :show-file-list="listType === 'picture-card' ? true : false"
      :list-type="listType"
      :on-preview="handlePictureCardPreview"
      :on-remove="handleRemove"
    >
      <slot>
        <el-button type="primary" :disabled="disabled">选择文件</el-button>
      </slot>
      <template v-if="showTip" #tip>
        <div class="m-t-10px leading-24px">
          <slot name="des">
            <div>
              <!-- <span>附件内容说明：</span> -->
              <span class="text-[#999999]">{{ tips }}</span>
            </div>
          </slot>
          <!-- <slot name="tips">
            <div>
              <span>请上传 大小不超过</span>
              <span class="color-#FA5940 m-l-2px m-r-2px">{{ size }}MB</span>
              <span>格式为</span>
              <span class="color-#FA5940 m-l-2px m-r-2px">{{ fileType.join('/') }}</span>
              <span>的文件</span>
            </div>
          </slot> -->
        </div>
      </template>
      <template v-if="listType === 'picture-card'" #file="{ file }">
        <div v-if="!handelFileType(file.name)" class="custom-preview-card">
          <div class="file-type-icon cursor-pointer" @click="handlePictureCardDown(file)">
            <el-icon :size="32"><Document /></el-icon>
          </div>
        </div>
      </template>
    </el-upload>
    <div v-if="loading" class="text-12px color-#999">{{ loadingtext }}</div>

    <transition-group v-if="listType !== 'picture-card'" class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
      <li v-for="(file, index) in fileList" :key="file.uid" class="el-upload-list__item ele-upload-list__item-content">
        <div class="ele-upload-list__item-content upload-item">
          <div class="curpor-pointer" @click="handlePictureCardDown(file)">
            <span class="el-icon-document cursor-pointer pl-9px">{{ file.name }} </span>
          </div>
          <div class="ele-upload-list__item-content-action">
            <el-link :underline="false" type="danger" :disabled="disabled" @click="handleDelete(index)">删除 </el-link>
          </div>
        </div>
      </li>
    </transition-group>

    <el-image-viewer v-if="dialogVisible" :url-list="[dialogImageUrl]" @close="dialogVisible = false" />
  </div>
</template>

<script lang="ts" setup>
  import type { PropType } from 'vue'
  import { ref } from 'vue'
  import { uploadV2, creatFile } from '~/api/common/index'
  import { Document } from '@element-plus/icons-vue'
  import type { UploadUserFile, UploadInstance } from 'element-plus'
  import { accDiv } from '~/utils/utils'
  // import CryptoJS from 'crypto-js' // 引入 crypto-js
  import dayjs from 'dayjs'

  const props = defineProps({
    disabled: {
      type: Boolean,
      default: false,
    },
    /** 文件个数限制 */
    limit: {
      type: Number,
      default: 1,
    },
    /** 文件大小限制(M) */
    size: {
      type: Number,
      default: 100,
    },
    /** 文件类型 */
    fileType: {
      type: Array as PropType<string[]>,
      // default: () => ['png', 'jpg', 'jpeg', 'doc', 'xls', 'ppt', 'pdf', 'txt'],
      default: () => [],
    },
    /** 上传地址 */
    uploadUrl: {
      type: String,
      default: '/prod-api/app-api/infra/file/presigned-url',
    },
    /** 提示文案 */
    tips: {
      type: String,
      default: '提供佐证变更有效的证明文件（邮件/聊天截图/情况说明）',
    },
    /** 提示文案 */
    showTip: {
      type: Boolean,
      default: true,
    },
    /** 是否预览cad */
    cadShow: {
      type: Boolean,
      default: false,
    },
    /** 组件类型 */
    listType: {
      type: String as PropType<'text' | 'picture' | 'picture-card'>,
      default: 'text', // picture" | "text" | "picture-card
    },
  })

  const emit = defineEmits(['validate', 'preview'])
  const uploadRef = ref<UploadInstance>()
  const fileList = defineModel<any>('fileList', {
    default: [],
  })

  const fileChange = ref()
  const handleChange = async (uploadFile: UploadUserFile) => {
    if (uploadFile.status !== 'ready') return
    /** 上传前校验 */
    if (handleBeforeUpload(uploadFile)) {
      fileChange.value = uploadFile
      // 新增：清除上传组件内部缓存
      uploadRef.value?.handleRemove(fileChange.value) // 关键：主动触发上传组件的remove方法
      return
    }
    /** 上传 */
    await handleUploadFile(uploadFile)
  }
  /** 上传前校验 */
  const handleBeforeUpload = (rawFile: UploadUserFile) => {
    if (fileList.value.length + 1 > props.limit) {
      handleExceed()
      return true
    }
    if (props.size > 0 && rawFile.size && +accDiv(accDiv(rawFile.size, 1024), 1024) > props.size) {
      ElMessage.error(`文件大小不能超过${props.size}M`)
      return true
    }
    const ext = rawFile.name.split('.').pop()?.toLowerCase()
    if (ext && props.fileType?.length && !props.fileType.includes(ext)) {
      ElMessage.error(`文件格式不正确, 请上传${props.fileType.join('/')}格式文件!`)
      return true
    }
  }
  const handleExceed = () => {
    ElMessage.error(`最多只能上传 ${props.limit} 个文件`)
  }
  const handleUploadError = (err: any) => {
    ElMessage.error('文件上传失败：' + err.message)
  }

  /** 上传 */
  const loading = ref(false)
  const loadingtext = ref('上传中...')
  const uploadUrlV2 = ref('')
  const fileUrl = ref('')
  const configId = ref('')
  const path = ref('')
  const getUploadConfig = async (options: UploadUserFile) => {
    path.value = `${options.uid}/${dayjs(new Date()).format('YYYY/MM/DD/HH/mm/ss')}/${options.name}`
    try {
      const response = await uploadV2(props.uploadUrl, { path: path.value })
      if (response.code !== 0) return ElMessage.error(response.message)
      uploadUrlV2.value = response.data.uploadUrl
      fileUrl.value = response.data.url
      configId.value = response.data.configId
    } catch (err) {
      loading.value = false
      console.error('获取上传配置失败:', err)
      alert('获取上传参数失败，请重试')
    }
  }

  /** 上传到服务器 */
  const UploadFilled = async (options: UploadUserFile) => {
    try {
      const res = await creatFile({
        configId: Number(configId.value),
        path: path.value,
        name: options.name,
        url: fileUrl.value,
        size: options.size as number,
      })
      if (res.code !== 0) return ElMessage.error(res.message)
      ElMessage.success('上传成功')
      const newFile = {
        name: options?.name,
        url: fileUrl.value,
        size: options?.size,
        uid: options.uid,
        title: options?.name,
        fileId: res.data,
      }
      // 更新文件列表
      fileList.value = [...fileList.value, newFile]
      emit('validate')
    } catch (error) {
      console.error('获取上传配置失败:', error)
      alert('creatFile上传失败，请重试')
    } finally {
      loading.value = false
    }
  }

  /** fetch 监听不了进度  需要改成xhr */
  const uploadWithProgress = (url: string, file: any, onProgress: (percent: number) => void) => {
    return new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest()
      xhr.open('PUT', url, true)
      xhr.setRequestHeader('Content-Type', file.raw.type)

      xhr.upload.onprogress = function (event) {
        if (event.lengthComputable) {
          const percent = Math.round((event.loaded / event.total) * 100)
          onProgress(percent)
        }
      }

      xhr.onload = function () {
        if (xhr.status >= 200 && xhr.status < 300) {
          resolve(xhr.response)
        } else {
          reject(new Error('上传失败'))
        }
      }

      xhr.onerror = function () {
        reject(new Error('网络错误'))
      }

      xhr.send(file.raw)
    })
  }
  const handleUploadFile = async (options: UploadUserFile) => {
    try {
      loading.value = true
      await getUploadConfig(options)
      // 使用PUT或POST方法上传（根据后端要求）
      // const response = await fetch(uploadUrlV2.value, {
      //   method: 'PUT', // 或 POST，根据后端预签名URL的规则
      //   body: options.raw,
      //   headers: {
      //     'Content-Type': (options.raw as Blob).type, // 设置文件类型
      //   },
      //   // onUploadProgress: (progressEvent: ProgressEvent) => {
      //   //   const percentCompleted = Math.round((progressEvent.loaded / progressEvent.total) * 100)
      //   //   loadingtext.value = `上传中...${percentCompleted}%`
      //   // },
      // })

      // if (response.ok) {
      //   await UploadFilled(options)
      //   // 此时文件已上传至OSS，fileUrl即为访问地址
      //   console.log('文件访问URL:', fileUrl.value)
      // } else {
      //   loading.value = false
      //   throw new Error('上传文件失败')
      // }
      const response = await uploadWithProgress(uploadUrlV2.value, options, (percent) => {
        loadingtext.value = `上传中...${percent}%`
      })
      if (response) {
        // 错误处理
        loading.value = false
        return ElMessage.error(options.name + '上传错误')
      }
      await UploadFilled(options)
    } catch (error) {
      loading.value = false
      ElMessage.error(options.name + '上传错误')
    }
  }

  /*** 删除 */
  const handleDelete = (index: number) => {
    fileList.value.splice(index, 1)
    emit('validate')
  }

  const dialogImageUrl = ref('')
  const dialogVisible = ref(false)
  const handleRemove = (uploadFile: any, uploadFiles: any) => {
    console.log(uploadFile, uploadFiles)
    fileList.value = fileList.value.filter((item: any) => item.uid !== uploadFile.uid)
    emit('validate')
  }

  const handlePictureCardPreview = (uploadFile: any) => {
    dialogImageUrl.value = uploadFile.url
    dialogVisible.value = true
  }

  const handlePictureCardDown = (uploadFile: any) => {
    if (props.cadShow) {
      emit('preview', uploadFile)
    } else {
      window.open(uploadFile.url)
    }
  }
  // 生成 MD5 唯一标识符
  // const generateMd5 = () => {
  //   const timestamp = new Date().getTime() // 获取当前时间戳
  //   const randomString = Math.random().toString(36).substring(2) // 生成随机字符串
  //   const data = `${timestamp}${randomString}` // 组合时间戳和随机字符串
  //   return CryptoJS.MD5(data).toString() // 生成 MD5 哈希值
  // }

  // 判断是否是图片
  const handelFileType = (fileName: string) => {
    const ext = fileName.split('.').pop()?.toLowerCase() || ''
    return ['png', 'jpg', 'jpeg'].includes(ext)
  }
</script>

<style lang="scss" scoped>
  .custom-preview-card {
    position: relative;
    width: 100%;
    height: 100%;
    .file-type-icon {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -40%);
    }
  }
  .upload-file {
    ::v-deep(.el-upload-dragger) {
      border: none !important;
      padding: 0;
      text-align: left;
    }
  }

  .upload-file-list .el-upload-list__item {
    line-height: 2;
    margin-bottom: 10px;
    position: relative;
    min-width: 361px;
  }

  .upload-file-list .ele-upload-list__item-content {
    display: flex;
    justify-content: space-between;
    align-items: center;
    color: inherit;
  }

  .upload-item {
    border: 1px solid #e4e7ed;
    border-radius: 5px;
    flex: 1;
    word-break: break-all;
  }

  .ele-upload-list__item-content-action .el-link {
    margin-right: 10px;
    width: 30px;
  }

  .el-upload-list--picture-card .el-upload-list__item {
    height: 81px !important;
  }

  // ::v-deep(.el-upload--picture-card) {
  //   height: 81px !important;
  // }

  // ::v-deep(.el-upload-list--picture-card) {
  //   .el-upload-list__item {
  //     height: 82px !important;
  //   }
  // }

  ::v-deep(.el-upload-list--picture-card) {
    .el-upload-list__item {
      width: 161px;
      height: 81px;
      // margin: 0 8px 8px 0;
    }
    .el-upload--picture-card {
      width: 161px;
      height: 81px;
    }
  }

  ::v-deep(.el-loading-spinner) {
    .circular {
      width: 32px !important;
      height: 32px !important;
      margin-top: 5px !important;

      .path {
        stroke-width: 3px;
      }
    }
  }

  ::v-deep(.el-loading-spinner i) {
    font-size: 32px !important;
  }
</style>
