<template>
  <el-dialog v-model="visible" :title="title" width="640px" destroy-on-close @closed="handleClosed">
    <div class="import-dialog">
      <section class="import-step">
        <div class="import-step__title">1. 下载模板</div>
        <el-button type="primary" :loading="downloadLoading" :icon="Download" @click="handleDownload"> 下载模板 </el-button>
      </section>
      <section class="import-step import-step--upload">
        <div class="import-step__title">2. 上传文件</div>
        <div class="import-upload-wrapper">
          <el-upload
            ref="uploadRef"
            drag
            action="#"
            :auto-upload="false"
            :limit="1"
            :show-file-list="true"
            :on-change="handleFileChange"
            :on-exceed="handleFileExceed"
            :on-remove="handleFileRemove"
            accept=".xls,.xlsx"
          >
            <el-icon class="el-icon--upload">
              <upload-filled />
            </el-icon>
            <div class="el-upload__text">将文件拖到此处，或<em>点击上传</em></div>
            <template #tip>
              <div class="el-upload__tip">仅支持 .xls / .xlsx 文件，大小不超过 {{ fileLimitMB }}M</div>
            </template>
          </el-upload>
        </div>
      </section>
    </div>
    <template #footer>
      <el-button @click="visible = false"> 取 消 </el-button>
      <el-button type="primary" :loading="submitLoading" @click="handleSubmit"> 保存 </el-button>
    </template>
  </el-dialog>
</template>

<script setup lang="ts">
import { computed, ref } from "vue";
import { ElMessage, type UploadInstance, type UploadProps, type UploadRawFile } from "element-plus";
import { Download, UploadFilled } from "@element-plus/icons-vue";

const props = withDefaults(
  defineProps<{
    modelValue: boolean;
    title?: string;
    downloadHandler: () => Promise<any>;
    importHandler: (formData: FormData) => Promise<any>;
    fileLimitMB?: number;
  }>(),
  {
    title: "导入数据",
    fileLimitMB: 10
  }
);

const emits = defineEmits<{
  "update:modelValue": [boolean];
  success: [];
}>();

const visible = computed({
  get: () => props.modelValue,
  set: val => emits("update:modelValue", val)
});

const uploadRef = ref<UploadInstance>();
const selectedFile = ref<UploadRawFile>();
const submitLoading = ref(false);
const downloadLoading = ref(false);
const fileLimitMB = computed(() => props.fileLimitMB);

const handleDownload = async () => {
  if (!props.downloadHandler) return;
  downloadLoading.value = true;
  try {
    await props.downloadHandler();
  } finally {
    downloadLoading.value = false;
  }
};

const validateAndSetFile = (file: UploadRawFile) => {
  const isExcel =
    file.type === "application/vnd.ms-excel" || file.type === "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
  const isLimit = file.size / 1024 / 1024 <= fileLimitMB.value;
  if (!isExcel) {
    ElMessage.warning("请上传 xls 或 xlsx 格式文件");
    return false;
  }
  if (!isLimit) {
    ElMessage.warning(`文件大小不能超过 ${fileLimitMB.value}M`);
    return false;
  }
  selectedFile.value = file;
  return true;
};

const handleFileChange: UploadProps["onChange"] = uploadFile => {
  const file = uploadFile.raw as UploadRawFile | undefined;
  if (!file) return;
  if (!validateAndSetFile(file)) {
    uploadRef.value?.clearFiles();
  }
};

const handleFileExceed: UploadProps["onExceed"] = files => {
  uploadRef.value?.clearFiles();
  const file = files[0] as UploadRawFile;
  if (!validateAndSetFile(file)) return;
  uploadRef.value?.handleStart(file);
};

const handleFileRemove: UploadProps["onRemove"] = () => {
  selectedFile.value = undefined;
};

const handleSubmit = async () => {
  if (!selectedFile.value) {
    ElMessage.warning("请先上传文件");
    return;
  }
  const formData = new FormData();
  formData.append("file", selectedFile.value);
  submitLoading.value = true;
  try {
    await props.importHandler(formData);
    ElMessage.success("导入成功");
    emits("success");
    visible.value = false;
  } finally {
    submitLoading.value = false;
  }
};

const handleClosed = () => {
  uploadRef.value?.clearFiles();
  selectedFile.value = undefined;
};
</script>

<style scoped lang="scss">
.import-dialog {
  display: flex;
  flex-direction: column;
  gap: 20px;
  max-width: 560px;
  margin: 0 auto;
}
.import-step {
  display: flex;
  justify-content: space-between;
  padding: 16px 20px;
  background-color: var(--el-bg-color);
  border: 1px solid var(--el-border-color);
  border-radius: 10px;
  box-shadow: 0 4px 12px rgb(0 0 0 / 6%);
  &__title {
    font-size: 15px;
    font-weight: 600;
    color: var(--el-text-color-primary);
    text-align: left;
  }
}
.import-step--upload {
  flex-direction: column;
  gap: 16px;
}
.import-upload-wrapper {
  display: flex;
  justify-content: center;
  width: 100%;
  :deep(.el-upload-dragger) {
    padding: 24px 16px;
    text-align: center;
    background-color: #f8fafc;
    border-style: dashed;
    border-radius: 12px;
  }
  :deep(.el-upload__text em) {
    color: var(--el-color-primary);
  }
  :deep(.el-upload__tip) {
    text-align: center;
  }
}
</style>
