<template>
  <el-upload
    ref="uploadRef"
    :action="uploadUrl"
    :headers="headers"
    :data="uploadDataDict"
    :show-file-list="false"
    :http-request="customRequest"
    :disabled="disabled"
    :before-upload="handleBeforeUpload"
    :accept="accept"
    :multiple="multiple"
    :on-exceed="handleExceededSize"
    @change="handleFileChange"
    @error="handleError"
    @success="handleSuccess"
  >
    <template #trigger>
      <el-button type="primary" :disabled="loading">{{ btnText }}</el-button>
    </template>
  </el-upload>
</template>

<script setup lang="ts">
  import { ref, computed } from 'vue';
  import { fileMD5 } from '@/utils/md5';
  import { ElMessage } from 'element-plus';
  import type {
    UploadRequestOptions,
    UploadFile,
    UploadFiles,
    UploadRawFile,
    UploadProgressEvent,
  } from 'element-plus';
  import axios, { AxiosHeaders } from 'axios';

  defineOptions({
    name: 'UploadButton',
  });

  const props = withDefaults(
    defineProps<{
      uploadUrl: string;
      uploadData?: Record<string, any>;
      maxSize?: number;
      uploadFileAlias?: string;
      autoUpload?: boolean;
      disabled?: boolean;
      btnText?: string;
      format?: string[];
      multiple?: boolean;
    }>(),
    {
      uploadUrl: '',
      uploadData: () => {
        return {};
      },
      format: () => ['xls', 'xlsx'],
      maxSize: 20 * 1024 * 1024,
      uploadFileAlias: 'file',
      autoUpload: true,
      disabled: false,
      btnText: '选择',
      multiple: false,
    }
  );

  const emit = defineEmits([
    'uploading',
    'uploadError',
    'uploadSuccess',
    'validError',
    'fileReady',
  ]);

  const uploadRef = ref();
  const canUpload = ref(false);
  const uploadDataDict = ref({});
  const headers = ref({ md5: '' });
  const result = ref({ success: true, message: '' });
  const loading = ref(false);

  const accept = computed(() => {
    return props.format.map((el) => `.${el}`).join();
  });

  function checkFileFormat(fileType: string) {
    const fileFormat = fileType.split('.').pop()?.toLocaleLowerCase();
    return props.format.some((item) => item.toLocaleLowerCase() === fileFormat);
  }

  function handleFileChange(uploadFile: UploadFile, uploadFiles: UploadFiles) {
    if (props.autoUpload || !uploadFiles.length) return;
    // Element Plus's status: ready, uploading, success, fail
    // Arco's status: init, uploading, success, error
    // We'll assume 'ready' is similar to 'init' for this logic, though direct mapping might not be perfect.
    canUpload.value = uploadFiles[0]?.status === 'ready';
  }

  async function handleBeforeUpload(file: UploadRawFile) {
    uploadDataDict.value = {
      ...props.uploadData,
      filename: file.name,
    };

    if (file.size > props.maxSize) {
      handleExceededSize();
      return Promise.reject(result.value);
    }

    if (!checkFileFormat(file.name)) {
      handleFormatError();
      return Promise.reject(result.value);
    }

    const md5 = await fileMD5(file);
    headers.value.md5 = md5;

    if (!props.autoUpload) {
      console.log('111');

      emit('fileReady', {
        md5,
        filename: file.name,
        file,
      });
      return Promise.reject();
    }

    loading.value = true;
    return Promise.resolve();
  }

  function customRequest(options: UploadRequestOptions) {
    // Changed return type to any
    const { onProgress, file, data } = options;

    const formData = new FormData();
    const paramData: Record<string, any> = data || {};
    Object.entries(paramData).forEach(([k, v]) => {
      formData.append(k, v);
    });
    formData.append(props.uploadFileAlias, file as File);
    emit('uploading');

    return axios.post(options.action, formData, {
      headers: options.headers as AxiosHeaders,
      onUploadProgress: ({ loaded, total }) => {
        onProgress({
          percent: total ? Math.floor((100 * loaded) / total) : 0,
        } as UploadProgressEvent);
      },
    });
  }

  function handleError(error: Error) {
    canUpload.value = false;
    loading.value = false;
    result.value = {
      success: false,
      message: error.message || '上传失败',
    };
    ElMessage.error(result.value.message);
    emit('uploadError', result.value);
  }
  function handleSuccess(response: any, uploadFile: UploadFile) {
    canUpload.value = false;
    loading.value = false;
    result.value = {
      success: true,
      message: '上传成功！',
    };
    ElMessage.success('上传成功！');
    emit('uploadSuccess', {
      ...result.value,
      filename: uploadFile.name,
      response,
    });
  }

  function handleFormatError() {
    const content = `只支持文件格式为${props.format.join('/')}`;
    result.value = {
      success: false,
      message: content,
    };
    loading.value = false;
    ElMessage.error(content);
    emit('validError', result.value);
  }
  function handleExceededSize() {
    const content = `文件大小不能超过${Math.floor(
      props.maxSize / (1024 * 1024)
    )}M`;
    result.value = {
      success: false,
      message: content,
    };
    loading.value = false;
    ElMessage.error(content);
    emit('validError', result.value);
  }
</script>
