<script setup lang="ts">
import { computed, ref, watch } from 'vue';
import type { UploadFileInfo } from 'naive-ui';
import { isExternal } from '@/utils/ruoyi';
import { getAuthorization } from '@/service/request/shared';
import { getServiceBaseURL } from '@/utils/service';

defineOptions({
  name: 'ImageUpload'
});

// 上传服务器地址
// const baseUrl = import.meta.env.VITE_BASE_URL;
const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y';
const { baseURL } = getServiceBaseURL(import.meta.env, isHttpProxy);
const uploadUrl = `${import.meta.env.VITE_SERVICE_BASE_URL}/${import.meta.env.VITE_SERVICE_UPLOAD}`;

const headers = {
  Authorization: getAuthorization()
};

interface Props {
  maxCount?: number; // 最大上传数量
  maxSize?: number; // 最大文件大小(MB)
  accept?: string[]; // 允许的文件类型
  multiple?: boolean; // 是否支持多选
  defaultUpload?: boolean; // 是否默认上传
  url?: string; // 上传地址
}

const props = withDefaults(defineProps<Props>(), {
  maxCount: 1,
  maxSize: 15,
  accept: () => ['.jpg', '.jpeg', '.png', '.gif'],
  multiple: true,
  defaultUpload: true,
  url: ''
});

const action = computed(() => {
  if (props.url) {
    return `${import.meta.env.VITE_SERVICE_BASE_URL}/${props.url}`;
  }
  return uploadUrl;
});

// 拿到的是File对象
const fileListObj = defineModel<File[]>('value', { default: () => [] });
const modelValue = defineModel<string>('modelValue');

const isMultiple = computed(() => {
  if (props.maxCount === 1) return false;
  return props.multiple;
});

// 文件列表
const fileList = ref<UploadFileInfo[]>([]);

watch(
  () => modelValue.value,
  val => {
    if (val) {
      // 将值转换为数组
      let list: string[] = [];

      // 确保 list 是数组，如果是字符串，则 split 成数组
      if (Array.isArray(val)) {
        list = val;
      } else if (typeof val === 'string') {
        list = val.split(',');
      }

      // 转换为符合要求的对象数组
      fileList.value = list.map((item, index) => {
        let name = '';
        let url = '';

        if (typeof item === 'string') {
          // 检查是否为外部链接或需要补全 baseURL
          if (!item.includes(baseURL) && !isExternal(item)) {
            url = `${baseURL}${item}`;
            name = item.split('/').pop() || '未知文件';
          } else {
            url = item;
            name = item.split('/').pop() || '未知文件';
          }
        }
        return {
          id: String(index + 1),
          name,
          status: 'finished',
          url
        };
      });
    } else {
      fileList.value = [];
    }
    modelValue.value = listToString(fileList.value);
  },
  { deep: true, immediate: true }
);

// 上传前校验
const beforeUpload = (data: { file: UploadFileInfo }) => {
  // 检查文件大小
  if (data.file.file) {
    const sizeInMB = data.file.file.size / 1024 / 1024;
    if (sizeInMB > props.maxSize) {
      window.$message?.error(`文件大小不能超过${props.maxSize}MB`);
      return false;
    }
  }
  // 检查文件类型
  if (data.file.file) {
    const fileName = data.file.file.name;
    const ext = fileName.substring(fileName.lastIndexOf('.')).toLowerCase();
    if (!props.accept.includes(ext)) {
      window.$message?.error(`只支持${props.accept.join('、')}格式`);
      return false;
    }
  }
  return true;
};

// 上传完成
const handleSuccess = ({ event }: { event: Event }) => {
  const target = event.target as XMLHttpRequest;
  const res = JSON.parse(target.response);
  fileList.value.push({
    id: String(fileList.value.length + 1),
    name: res.data.name,
    status: 'finished',
    url: res.data.url
  });
  modelValue.value = listToString(fileList.value);
};

// 删除文件
const handleRemove = ({ index }: { index: number }) => {
  fileList.value.splice(index, 1);
  modelValue.value = listToString(fileList.value);
};

function handleChange(options: { fileList: UploadFileInfo[] }) {
  fileListObj.value = options.fileList.map(item => item.file) as File[];
}

// 对象转成指定字符串分隔
function listToString(list: UploadFileInfo[], separator = ',') {
  return list
    .map(item => item.url)
    .filter(url => url && !url.startsWith('blob:'))
    .join(separator);
}
</script>

<template>
  <NUpload
    :action="action"
    :headers="headers"
    :max="maxCount"
    :default-file-list="fileList"
    list-type="image-card"
    :accept="accept.map(item => `.${item}`).join(',')"
    :multiple="isMultiple"
    :default-upload="defaultUpload"
    @before-upload="beforeUpload"
    @finish="handleSuccess"
    @remove="handleRemove"
    @change="handleChange"
  >
    点击上传
  </NUpload>
</template>

<style scoped></style>
