<template>
  <div>
    <div class="flex upload-toolbar">
      <Upload
        :accept="getStringAccept"
        :multiple="multiple"
        :before-upload="beforeUpload"
        :show-upload-list="false"
        class="upload-toolbar__btn"
      >
        <a-button>
          <upload-outlined />
          上传文件
        </a-button>
      </Upload>
      <Alert :message="getHelpText" type="info" banner class="upload-toolbar__text" />
    </div>
    <div class="upload-filelist">
      <!-- <div>已上传</div> -->
      <div class="upload-filelist__item" v-for="item in fileList" :key="item.id">
        <div>
          <paper-clip-outlined class="mr-1" />
          <span class="mr-2">{{ item.realName }}</span>
          <span class="color-muted">({{ item.size }}kb)</span>
        </div>
        <div class="flex">
          <!-- <span class="mr-2">30%</span> -->
          <!-- <a :href="item.absolutePath" target="_blank" class="mr-2">预览</a> -->
          <span
            class="upload-filelist--color pointer"
            @click="handlePreview(item)"
            :title="'预览-' + item.realName"
            >预览</span
          >
          <span class="upload-filelist--color pointer" @click="handleRemove(item, 1)">删除</span>
        </div>
      </div>
    </div>
    <!-- <div v-if="fileListRef.length" @click="handleStartUpload">未上传</div> -->
    <div class="upload-filelist">
      <div
        :class="[
          'upload-filelist__item',
          item.status == 'error' ? 'upload-filelist__item--error' : '',
        ]"
        v-for="item in fileListRef"
        :key="item.uuid"
      >
        <div class="upload-filelist__item-info">
          <paper-clip-outlined class="mr-1" />
          <span class="mr-2">{{ item.name }}</span>
          <span>({{ item.size }}kb)</span>
        </div>
        <div class="upload-filelist__item-progress">
          <a-progress
            :percent="item.percent"
            size="small"
            :status="setProgressSataus(item.status)"
          />
        </div>
        <div class="flex">
          <span class="upload-filelist--error" v-if="item.status == 'error'">上传失败</span>
          <span class="upload-filelist--color pointer" @click="handleRemove(item, 0)">删除</span>
        </div>
      </div>
    </div>
    <!-- <FileList :dataSource="fileListRef" /> -->
    <UploadPreviewModal @register="registerPreviewModal" />
  </div>
</template>
<script lang="ts">
  import { UploadOutlined, PaperClipOutlined } from '@ant-design/icons-vue';
  import { PropType, defineComponent, reactive, ref, toRefs, unref, watch } from 'vue';
  import { Upload, Alert } from 'ant-design-vue';
  import { uploadContainerProps } from './props';
  import { FileItem, UploadResultStatus } from './typing';
  import { useModal } from '/@/components/Modal';
  // hooks
  import { useUploadType } from './useUpload';
  import { useMessage } from '/@/hooks/web/useMessage';
  // utils
  import { isFunction, isArray } from '/@/utils/is';
  import { warn } from '/@/utils/log';
  import { nanoid } from 'nanoid';
  import locales from '/@/utils/locales';
  // import { getPreviewUrl, postFileRemoveByIds } from '/@/api/common';
  import { getPreviewUrl } from '/@/api/common';
  import UploadPreviewModal from './UploadPreviewModal.vue';
  import { ResultEnum } from '@/enums/httpEnum';

  export default defineComponent({
    name: 'XTUpload',
    components: {
      UploadOutlined,
      PaperClipOutlined,
      Upload,
      Alert,
      UploadPreviewModal,
    },
    props: {
      ...uploadContainerProps,
      previewFileList: {
        type: Array as PropType<string[]>,
        default: () => [],
      },
    },
    emits: ['change', 'delete'],
    setup(props, { emit }) {
      const state = reactive<{ fileList: FileItem[] }>({
        fileList: [],
      });
      //   预览modal
      const [registerPreviewModal, { openModal: openPreviewModal }] = useModal();

      //   是否正在上传
      const isUploadingRef = ref(false);
      const fileList = ref<any[]>([]);
      const fileListRef = ref<FileItem[]>([]);
      const isMultiCount = ref(0);
      const previewFile = ref<any>({});
      const { accept, helpText, maxNumber, maxSize } = toRefs(props);

      const { getStringAccept, getHelpText } = useUploadType({
        acceptRef: accept,
        helpTextRef: helpText,
        maxNumberRef: maxNumber,
        maxSizeRef: maxSize,
      });

      const { createMessage } = useMessage();

      watch(
        () => props.value,
        (value = []) => {
          fileList.value = isArray(value) ? value : [];
          // console.log('🚀 ~ file: XTUpload.vue:80 ~ setup ~ fileList.value :', fileList.value);
        },
        { immediate: true },
      );

      // 上传前校验
      async function beforeUpload(file: File, fileList) {
        // console.log('🚀 ~ file: XTUpload.vue:142 ~ beforeUpload ~ file:', file);
        // console.log('🚀 ~ file: XTUpload.vue:142 ~ beforeUpload ~ fileList:', fileList);
        // console.log('几个文件', fileList.length);
        if (fileList.length == 1) {
          handleFile(file);
          await handleStartUpload();
        } else {
          isMultiCount.value += 1;
          // console.log('🚀 ~ file: XTUpload.vue:155 ~ beforeUpload ~ isMultiCount:', isMultiCount);
          // console.log('🚀 ~ file: XTUpload.vue:157 ~ beforeUpload ~ fileList:', fileList);
          if (isMultiCount.value == fileList.length) {
            console.log('上传操作');
            fileList.forEach(ele => {
              handleFile(ele);
            });
            await handleStartUpload();
          }
        }
        return false;
        // return false 会停止自动上传
      }
      // 设置上传文件
      function handleFile(file) {
        const { maxSize } = props;
        const { size, name } = file;
        // 设置最大值，则判断
        if (maxSize && file.size / 1024 / 1024 >= maxSize) {
          createMessage.error(`只能上传不超过${maxSize}MB的文件!`);
          return false;
        }
        const commonItem = {
          uuid: nanoid(5),
          file,
          size,
          name,
          percent: 0,
          type: name.split('.').pop(),
        };
        // 生成文件列表
        fileListRef.value = [...unref(fileListRef), commonItem];
      }
      // 删除
      async function handleRemove(record, bool) {
        if (bool) {
          const index = fileList.value.findIndex(item => item.id === record.id);
          index !== -1 && fileList.value.splice(index, 1);
          emit('delete', record);
          // await postFileRemoveByIds([record.id]);
        } else {
          const index = fileListRef.value.findIndex(item => item.uuid === record.uuid);
          index !== -1 && fileListRef.value.splice(index, 1);
          emit('delete', record);
        }
      }
      // 预览
      async function handlePreview(record) {
        // console.log('🚀 ~ file: XTUpload.vue:147 ~ handlePreview ~ record:', record);
        const res = await getPreviewUrl(record.id);
        console.log('预览数据', { ...record, previewUrl: res });
        previewFile.value = {
          ...record,
          previewUrl: res,
        };
        openPreviewModal(true, {
          ...record,
          previewUrl: res,
        });
      }
      // 进度状态渲染
      function setProgressSataus(uploadStatus) {
        let status: 'normal' | 'exception' | 'active' | 'success' = 'normal';
        if (uploadStatus === UploadResultStatus.ERROR) {
          status = 'exception';
        } else if (uploadStatus === UploadResultStatus.UPLOADING) {
          status = 'active';
        } else if (uploadStatus === UploadResultStatus.SUCCESS) {
          status = 'success';
        }
        return status;
      }
      async function uploadApiByItem(item: FileItem, idx: number, len: number) {
        const { api } = props;
        if (!api || !isFunction(api)) {
          return warn('upload api must exist and be a function');
        }
        try {
          // eslint-disable-next-line no-unsafe-optional-chaining
          const { data } = await props?.api?.(
            {
              data: {
                ...(props.uploadParams || {}),
              },
              file: item.file,
              name: props.name,
              filename: props.filename,
            },
            function onUploadProgress(progressEvent: ProgressEvent) {
              const complete = ((progressEvent.loaded / progressEvent.total) * 100) | 0;
              item.percent = complete;
            },
          );
          item.status =
            data.code == ResultEnum.SUCCESS ? UploadResultStatus.SUCCESS : UploadResultStatus.ERROR;
          item.responseData = data;
          // if (idx + 1 == len) {
          if (idx <= len) {
            // console.log('🚀 ~ file: XTUpload.vue:250 ~ uploadApiByItem ~ len:', len);
            // console.log(
            //   '🚀 ~ file: XTUpload.vue:259 ~ uploadApiByItem ~ fileListRef.value:',
            //   fileListRef.value,
            // );
            isMultiCount.value = 0;
            fileListRef.value.forEach(ele => {
              const responseData = ele.responseData as any;
              // console.log(
              //   '🚀 ~ file: XTUpload.vue:258 ~ uploadApiByItem ~ responseData:',
              //   responseData,
              // );
              if (responseData?.code == ResultEnum.SUCCESS) {
                fileList.value.push(responseData.data);
                // console.log(
                //   '🚀 ~ file: XTUpload.vue:256 ~ uploadApiByItem ~ fileList.value.push:',
                //   fileList.value,
                // );
              } else {
                responseData ? createMessage.error(responseData?.errorMsg) : '';
              }
            });
            fileListRef.value = fileListRef.value.filter(ele => {
              return (
                ele.status != UploadResultStatus.SUCCESS ||
                String(ele.responseData?.code) != ResultEnum.SUCCESS
              );
            });
          }

          return {
            success: data.code == ResultEnum.SUCCESS ? true : false,
            error: data.code == ResultEnum.SUCCESS ? null : data.errorMsg,
          };
        } catch (e) {
          console.log(e);
          item.status = UploadResultStatus.ERROR;
          return {
            success: false,
            error: e,
          };
        }
      }
      // 点击开始上传
      async function handleStartUpload() {
        const { maxNumber } = props;
        console.log('🚀 ~ file: XTUpload.vue:282 ~ handleStartUpload ~ props:', props);
        if ((fileListRef.value.length + fileList.value.length ?? 0) > maxNumber) {
          return createMessage.warning(`最多只能上传${maxNumber}个文件`);
        }
        try {
          isUploadingRef.value = true;
          // 只上传不是成功状态的
          const uploadFileList =
            fileListRef.value.filter(item => item.status !== UploadResultStatus.SUCCESS) || [];

          const data = await Promise.all(
            uploadFileList.map((item, idx) => {
              const result = uploadApiByItem(item, idx, uploadFileList.length);
              return result;
            }),
          );
          emit('change', fileList.value);
          isUploadingRef.value = false;
          // 生产环境:抛出错误
          const errorList = data.filter((item: any) => !item.success);
          if (errorList.length > 0) throw errorList;
        } catch (e) {
          isUploadingRef.value = false;
          throw e;
        }
      }

      return {
        getHelpText,
        getStringAccept,
        beforeUpload,
        fileListRef,
        state,
        isUploadingRef,
        handleStartUpload,
        locales,
        fileList,
        handleRemove,
        handlePreview,
        previewFile,
        registerPreviewModal,
        setProgressSataus,
      };
    },
  });
</script>

<style lang="less" scoped>
  .upload {
    .ant-upload-list {
      display: none;
    }

    .ant-table-wrapper .ant-spin-nested-loading {
      padding: 0;
    }

    &-toolbar {
      display: flex;
      align-items: center;
      margin-bottom: 8px;

      &__btn {
        text-align: left;
        margin-right: 8px;
      }

      &__text {
        height: 32px;
        width: 100%;
        flex: 1;
        white-space: nowrap;
        text-overflow: ellipsis;
        overflow: hidden;
      }
    }

    &-filelist {
      &__item {
        display: flex;
        justify-content: space-between;
        background-color: rgb(241 247 255 / 100%);
        margin-bottom: 4px;
        padding: 5px 8px;

        &--error {
          background-color: rgb(255 241 236 / 100%);
        }

        &-info {
          max-width: 220px;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
        }

        &-progress {
          min-width: 180px;
        }
      }

      &--color {
        color: rgb(0 117 255 / 100%);
        margin-left: 16px;
        min-width: 28px;
      }

      &--error {
        color: rgb(255 72 4 / 100%);
        margin-left: 16px;
      }
    }
  }
</style>
