<script setup lang="ts">
import { computed, ref, watch } from 'vue';

import { preferences } from '@vben/preferences';
import { Button, Upload } from 'ant-design-vue';
import { Icon } from '#/components/icon';
import { uploadFile } from '#/api/core/upload';
import { uploadToOss } from '#/utils/oss-upload';

interface FileItem {
  uid: string;
  name: string;
  status: 'uploading' | 'done' | 'error';
  url: string;
}

interface Props {
  modelValue?: string;
  maxCount?: number;
}

const props = withDefaults(defineProps<Props>(), {
  modelValue: '',
  maxCount: 1,
});

const emit = defineEmits<{
  'update:modelValue': [value: string];
}>();

const fileList = ref<FileItem[]>([]);

function syncFileListFromValue(url: string) {
  if (!url) {
    fileList.value = [];
    return;
  }
  fileList.value = [
    {
      uid: url,
      name: url.split('/').pop() || 'file',
      status: 'done',
      url,
    },
  ];
}

syncFileListFromValue(props.modelValue);

watch(
  () => props.modelValue,
  (newVal) => {
    const currentUrl =
      fileList.value.find((file) => file.status === 'done')?.url ?? '';
    if ((newVal ?? '') !== currentUrl) {
      syncFileListFromValue(newVal ?? '');
    }
  },
);

function updateModelValue() {
  const url =
    fileList.value.find((file) => file.status === 'done' && file.url)?.url ??
    '';
  emit('update:modelValue', url);
}

function beforeUpload(file: File) {
  const maxSize = 20 * 1024 * 1024;
  if (file.size > maxSize) {
    return Upload.LIST_IGNORE;
  }
  return true;
}

const customRequest = async (options: any) => {
  const { file, onProgress, onSuccess, onError } = options;

  fileList.value = [
    {
      uid: file.uid,
      name: file.name,
      status: 'uploading',
      url: '',
    },
  ];

  try {
    const uploadMethod = preferences.app.uploadMethod || 'direct';
    let res: { url: string };

    if (uploadMethod === 'direct') {
      res = await uploadToOss({
        file: file as File,
        onProgress: (percent) => {
          onProgress?.({ percent });
        },
      });
    } else {
      res = await uploadFile({
        file: file as File,
      });
    }

    fileList.value = [
      {
        uid: file.uid,
        name: file.name,
        status: 'done',
        url: res.url,
      },
    ];
    updateModelValue();
    onSuccess?.(res);
  } catch (error) {
    fileList.value = [
      {
        uid: file.uid,
        name: file.name,
        status: 'error',
        url: '',
      },
    ];
    onError?.(error);
  }
};

function handleRemove() {
  fileList.value = [];
  updateModelValue();
  return true;
}

const showUploadButton = computed(
  () => fileList.value.filter((item) => item.status !== 'error').length === 0,
);
</script>

<template>
  <Upload
    :file-list="fileList"
    :before-upload="beforeUpload"
    :custom-request="customRequest"
    :max-count="maxCount"
    list-type="text"
    accept=".pdf,.jpg,.jpeg,.png,.doc,.docx,image/*,application/pdf"
    @remove="handleRemove"
  >
    <Button v-if="showUploadButton">
      上传文件
      <template #icon>
        <Icon icon="ant-design:cloud-upload-outlined" />
      </template>
    </Button>
  </Upload>
</template>
