<template>
  <div class="simpleUploadDiv">
    <a-progress v-if="uploading" type="circle" :percent="percent" />
    <a-image
      height="80%"
      v-else
      :src="minioBaseUrl + modelValue"
      alt="avatar"
    />

    <a-button class="btn-success" @click="selectFile">{{ btnLabel }}</a-button>
    <input :id="id" type="file" style="display: none" ref="fileInput" />
  </div>
</template>

<script setup lang="ts">
import { message } from "ant-design-vue";
import { onMounted, onUnmounted, ref } from "vue";
import {
  generateSimpleObjectName,
  getResignedObjectUrl,
} from "@/utils/minioUtil";
import axios, { CancelTokenSource } from "axios";
import { convertFileSizeToStr } from "@/utils/index.ts";

const minioBaseUrl = __APP_ENV.VITE_APP_MINIO_URL;

const modelValue = defineModel<string>("value");
const props = withDefaults(
  defineProps<{
    parentDir?: string;
    allowedExtensions?: string[];
    maxSize?: number;
    width?: string | number;
    height?: string | number;
    btnLabel?: string;
    id: string;
  }>(),
  {
    parentDir: "",
    allowedExtensions: () => ["jpg", "jpeg", "png", "gif"],
    maxSize: 1024 * 1024 * 4,
    width: "150px",
    height: "150px",
    btnLabel: "选择图片",
    id: "myFileInput",
  }
);

const uploading = ref(false);
const percent = ref(0);
let cancelToken: CancelTokenSource | null = null;
const uploadUrl = ref();
const fileInput = ref(null);

const selectFile = () => {
  document.getElementById(props.id)?.click();
};

async function inputFileListener(this: HTMLInputElement) {
  const selectedFile: File = this.files?.[0] as File;
  const fileExtension = selectedFile.name
    ?.split(".")
    .pop()
    .toLowerCase() as string;

  if (!props.allowedExtensions.includes(fileExtension)) {
    return message.error(
      `错误：不支持的文件格式,目前支持:【${props.allowedExtensions}】`
    );
  }
  const isMax = selectedFile.size > props.maxSize;
  if (isMax) {
    return message.error(
      `文件大小超出限制，最大支持:【${convertFileSizeToStr(props.maxSize)}】`
    );
  }
  cancelToken?.cancel();
  percent.value = 0;
  uploading.value = true;

  const objectName = generateSimpleObjectName(
    selectedFile.name,
    props.parentDir
  );

  uploadUrl.value = await getResignedObjectUrl(
    __APP_ENV.VITE_APP_MINIO_BUCKET,
    objectName
  );
  cancelToken = axios.CancelToken.source();
  await axios.put(uploadUrl.value, selectedFile, {
    cancelToken: cancelToken.token,
    onUploadProgress: (progressEvent) => {
      percent.value =
        ((progressEvent.loaded / (progressEvent.total as number)) * 100) | 0;
    },
  });
  modelValue.value = "/" + __APP_ENV.VITE_APP_MINIO_BUCKET + objectName;
  uploading.value = false;
}

const fileDelete = () => {
  uploadUrl.value = "";
  fileInput.value.value = "";
  modelValue.value = "";
};
onMounted(() => {
  document
    .getElementById(props.id)
    ?.addEventListener("change", inputFileListener);
});

onUnmounted(() => {
  document
    .getElementById(props.id)
    ?.removeEventListener("change", inputFileListener);
});
defineExpose({ fileDelete });
</script>

<style scoped lang="scss">
.simpleUploadDiv {
  width: v-bind(width);
  height: v-bind(height);
  display: flex;
  flex-direction: column;
}
</style>
