<script lang="ts">
  export default {
    inheritAttrs: false,
  };
</script>
<script lang="ts" setup>
  import { Upload, Spin, Tooltip } from 'ant-design-vue';
  import { InboxOutlined } from '@ant-design/icons-vue';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { computed, ref, unref } from 'vue';
  import { cloneDeep } from 'lodash-es';
  import { isFunction, isNumber, isObject } from '/@/utils/is';
  import { useDesign } from '/@/hooks/web/useDesign';

  export interface FileItem {
    uid: string;
    name: string;
    status?: string;
    response?: string;
    url?: string;
  }

  const { prefixCls } = useDesign('api-upload');
  const emit = defineEmits(['update:fileList', 'preview', 'download']);

  const { createMessage } = useMessage();

  const loading = ref(false);

  const componentDisabled = ref(false);

  const setUploadStatus = (status: boolean) => {
    loading.value = status;
    componentDisabled.value = status;
  };

  const props = withDefaults(
    defineProps<{
      fileList?: FileItem[];
      accept?: string;
      maxSize?: number;
      disabled?: boolean;
      listType?: string;
      multiple?: boolean;
      maxFileLimit?: number;
      showUploadList?: boolean | { showPreviewIcon?: boolean; showRemoveIcon?: boolean };
      transformFile?: (file: File) => string | Blob | Promise<string | Blob | File>;
      api: (file: string | Blob | Promise<string | Blob | File>) => Promise<FileItem>;
    }>(),
    {
      fileList: () => [],
      maxSize: 5 * 1024 * 1024,
      showUploadList: () => ({ showPreviewIcon: true, showRemoveIcon: true }),
    }
  );

  const handleBeforeUpload = (file: File) => {
    if (file.size > props.maxSize) {
      createMessage.warning(`文件大小超过${Math.floor(props.maxSize / 1024 / 1024)}mb`);
      return false;
    }
    handleUpload(file);
    return false;
  };

  const getDisabled = computed(() => {
    const { disabled } = props;
    return disabled ? disabled : unref(componentDisabled);
  });

  const isPictureCard = computed(() => {
    const { listType } = props;
    return listType === 'picture-card';
  });

  const getMaxFileLimit = computed(() => {
    const { maxFileLimit } = props;
    return isPictureCard.value ? 1 : maxFileLimit;
  });

  const handleUpload = async (file: File | string | Blob | Promise<string | Blob | File>) => {
    try {
      setUploadStatus(true);
      const { transformFile, api } = props;
      if (transformFile && isFunction(transformFile)) file = await transformFile(file as File);
      if (api && isFunction(api)) {
        const data = await api(file);
        if (isObject(data) && Reflect.has(data, 'uid') && Reflect.has(data, 'name')) {
          const { fileList } = props;
          let _fileList = cloneDeep(fileList);

          if (isNumber(unref(getMaxFileLimit)) && _fileList.length === unref(getMaxFileLimit)) {
            _fileList.splice(0, 1);
          }

          emit('update:fileList', cloneDeep([..._fileList, data]));
          return;
        }
        window.console.error(
          `The ApiUpload component's api properties need to return an object, that object requires a uid field and a name field`
        );
      }
    } catch (error) {
      window.console.error(error);
    } finally {
      setUploadStatus(false);
    }
  };

  const handleRemove = (file: FileItem) => {
    const _fileList = cloneDeep(props.fileList);
    const index = _fileList.findIndex((item) => item.uid === file.uid);
    ~index && _fileList.splice(index, 1);
    emit('update:fileList', _fileList);
  };

  const handlePreview = (file: FileItem) => {
    emit('preview', file);
  };

  const handleDownload = (file: FileItem) => {
    emit('download', file);
  };
</script>

<template>
  <Upload
    class="block"
    :class="prefixCls"
    :file-list="props.fileList"
    :list-type="props.listType"
    :disabled="getDisabled"
    :before-upload="handleBeforeUpload"
    @preview="handlePreview"
    @download="handleDownload"
    :remove="handleRemove"
  >
    <Spin v-if="!fileList.length" :spinning="loading">
      <div class="w-full h-full flex flex-col justify-center content-center">
        <Tooltip title="点击上传或拖拽上传">
          <InboxOutlined class="text-[3rem] !text-blue-500" />
        </Tooltip>
        <div v-if="!isPictureCard" class="m-2 text-gray-400 text-sm">点击上传或拖拽上传</div>
      </div>
    </Spin>
  </Upload>
</template>

<style lang="less">
  @basic-form: ~'@{namespace}-basic-form';
  @prefix-cls: ~'@{namespace}-api-upload';

  .@{basic-form} {
    // .ant-form-item-control-input-content > div > div {
    //   width: 100% !important;
    // }

    .@{prefix-cls} {
      .ant-upload-list-item-name {
        width: calc(100% - 22px);
      }

      .ant-upload-select-text {
        width: 100%;
        text-align: center;
        border: 1px dashed #d9d9d9;
      }
    }
  }
</style>
