<script setup lang="ts">
import type { FileUploadState, FileUploadUploaderEvent } from 'primevue/fileupload';

import TimesIcon from '@primevue/icons/times';
import axios from 'axios';

interface FileExt extends File {
  objectURL: string;
}

interface FileUploadInst extends FileUploadState {
  chooseDisabled?: boolean;
  files: FileExt[];
  uploadedFiles: {
    name: string;
    progress: number;
    rawFile: FileExt;
    status: 'failed' | 'uploaded' | 'uploading';
    url: string;
  }[];
}
// https://primevue.org/toast/#headless

const fileUploadRef = useTemplateRef<FileUploadInst>('fileUploadRef');

const onUploader = (event: FileUploadUploaderEvent) => {
  console.debug(`event.files :>> `, event.files);
  const files = event.files as FileExt[];
  for (const file of files) {
    fileUploadRef.value!.uploadedFiles.push({
      name: file.name,
      progress: 0,
      rawFile: file,
      status: 'uploading',
      url: '',
    });
    const formData = new FormData();
    formData.append('file', file);
    axios
      .post('/fake-api/fake/upload', formData, {
        headers: { 'Content-Type': 'multipart/form-data' },
        onUploadProgress: (e) => {
          const progress = Math.round((e.loaded * 100) / (e.total || 1));
          const item = fileUploadRef.value!.uploadedFiles.find((f) => f.rawFile === file);
          if (item) {
            item.progress = progress;
          }
        },
      })
      .then((res) => {
        console.debug(`res :>> `, res);
        const item = fileUploadRef.value!.uploadedFiles.find((f) => f.rawFile === file);
        if (item) {
          item.status = 'uploaded';
          item.url = res.data.url;
        }
      })
      .catch((error) => {
        console.error(`err :>> `, error);
        const item = fileUploadRef.value!.uploadedFiles.find((f) => f.rawFile === file);
        if (item) {
          item.status = 'failed';
        }
      });
  }
};

// https://github.com/primefaces/primevue/issues/4722#issuecomment-2241581616
// const fileObjectURL = (file: File) => window.URL.createObjectURL(file);

// const TemplateFoo = createReusableTemplate<{ msg: string }>();

const uploadedFiles = computed(() => fileUploadRef.value?.uploadedFiles || []);
const files = computed(() => fileUploadRef.value?.files || []);

const showUploadButton = computed(() => {
  if (fileUploadRef.value?.files?.length) {
    return true;
  }
  return false;
});

const fileLimit = 2;
const disabled = computed(() => {
  if (fileUploadRef.value?.uploadedFiles?.some((f) => f.status === 'failed')) {
    return true;
  }
  if ((fileUploadRef.value?.uploadedFileCount || 0) >= fileLimit) {
    return true;
  }
  return false;
});
</script>

<template>
  <FileUpload
    ref="fileUploadRef"
    :auto="true"
    :disabled="disabled"
    :showUploadButton="showUploadButton"
    :showCancelButton="false"
    customUpload
    mode="advanced"
    :multiple="true"
    accept="image/*"
    :maxFileSize="1000000 * 1"
    invalidFileSizeMessage="文件 {0} 大小超过限制 {1}"
    :fileLimit="fileLimit"
    invalidFileLimitMessage="最多只能上传 {0} 个文件，请移除多余文件后点击上传"
    @uploader="onUploader"
    :chooseButtonProps="{ size: 'small' }"
    :uploadButtonProps="{ size: 'small', severity: 'secondary' }"
    :cancelButtonProps="{ size: 'small', severity: 'secondary' }"
  >
    <template #empty>
      <Message size="small" severity="info">请上传图片</Message>
    </template>
    <template #content="{ messages, removeFileCallback, removeUploadedFileCallback }">
      <Message
        size="small"
        v-for="msg of messages"
        closable
        @close="fileUploadRef!.messages = []"
        :key="msg"
        severity="error"
        >{{ msg }}</Message
      >

      <!-- 待上传列表 -->
      <template v-for="(file, index) of files" :key="file.name + file.type + file.size">
        <div class="border p-2 rounded-md flex flex-wrap items-center gap-2">
          <img alt="" :src="file.objectURL" class="w-10 h-10 shrink-0" />
          <div class="break-all break-anywhere">{{ file.name }}</div>
          <Badge value="待上传" severity="warn" />
          <Button text :rounded="true" severity="danger" class="ml-auto" @click="removeFileCallback(index)">
            <TimesIcon aria-hidden="true" />
          </Button>
        </div>
      </template>

      <!-- 已上传列表（上传中、上传成功、上传失败） -->
      <template v-for="(file, index) of uploadedFiles" :key="file.name + file.url">
        <div class="border p-2 rounded-md flex flex-wrap items-center gap-2">
          <img alt="" :src="file.url || file.rawFile.objectURL" class="w-10 h-10 shrink-0" />
          <div class="break-all break-anywhere">{{ file.name }}</div>
          <Badge
            :value="file.status === 'uploading' ? '上传中' : file.status === 'uploaded' ? '已上传' : '上传失败'"
            :severity="file.status === 'uploading' ? 'warn' : file.status === 'uploaded' ? 'success' : 'danger'"
          />
          <Button
            text
            :rounded="true"
            severity="danger"
            class="ml-auto"
            @click="
              fileUploadRef!.uploadedFileCount--;
              removeUploadedFileCallback(index);
            "
          >
            <TimesIcon aria-hidden="true" />
          </Button>
          <ProgressBar v-if="file.status === 'uploading'" :value="file.progress" />
        </div>
      </template>

      <div>files.length: {{ files.length }}</div>
      <div>uploadedFiles.length: {{ uploadedFiles.length }}</div>
      <div>uploadedFileCount: {{ fileUploadRef?.uploadedFileCount }}</div>
    </template>
  </FileUpload>
</template>

<style></style>
