<script lang="ts" setup>
import { Upload, Download } from "@icon-park/vue-next";
import BaseForm from "../base-form/BaseForm.vue";
import { ElMessage, type UploadInstance, type UploadUserFile } from "element-plus";
import * as XLSX from "xlsx";
import { type ExcelColumnConfig, type FieldMappingConfig, type DetailLoadConfig } from "./type";
import { Delete } from "@element-plus/icons-vue";
import { get } from "@/common/http/request";
import { $t } from "@/common/languages";

interface Emits {
  (e: "error", msg: string): void;
}

const props = defineProps({
  baseTitle: String,
  tableTitle: String,
  itemArrayName: { type: String, required: true },
  mappingConfig: { type: Object as () => FieldMappingConfig, required: true },
  templateFileName: { type: String, required: true },
  /**
   * 明细数据加载配置
   * 传入此配置后，组件会在编辑模式下自动加载明细数据
   */
  detailConfig: { type: Object as () => DetailLoadConfig | null, default: null },
  /**
   * 模板列配置
   * 用于控制模板中显示哪些列，如果不传则使用 mappingConfig 中的所有列
   * 可以设置 include 或 exclude 来控制列的显示
   * include: 只包含指定的列
   * exclude: 排除指定的列
   */
  templateColumns: {
    type: Object as () => {
      include?: string[];
      exclude?: string[];
    } | null,
    default: null,
  },
});

const emit = defineEmits<Emits>();
const form = defineModel<any>("form");
const visible = defineModel<boolean>("visible");
const uploadRef = ref<UploadInstance>();
const baseFormRef = ref<InstanceType<typeof BaseForm> | null>(null);

// 加载状态
const loading = ref(false);

/**
 * 获取 Excel 列配置
 * 统一处理为数组形式
 */
const getSourceKeys = (config: ExcelColumnConfig): string[] => {
  const { sourceKey } = config;
  if (Array.isArray(sourceKey)) {
    return sourceKey;
  }
  return [sourceKey];
};

/**
 * 获取表头文本
 * 优先使用 header，如果没有则使用 sourceKey 的第一个值
 */
const getHeaderText = (config: ExcelColumnConfig): string => {
  if (config.header) {
    return config.header;
  }
  const sourceKeys = getSourceKeys(config);
  return sourceKeys[0] || "";
};

/**
 * 从行数据中获取值
 */
const getValue = (row: any, config: ExcelColumnConfig) => {
  const sourceKeys = getSourceKeys(config);
  const { defaultValue, transform } = config;
  let rawValue: any;

  // 1. 处理 sourceKey 是数组的情况 (多对一 / 降级策略)
  for (const key of sourceKeys) {
    const val = row[key];
    // 只要找到非 undefined 且非 null 的值，就立即停止查找
    if (val !== undefined && val !== null && val !== "") {
      rawValue = val;
      break;
    }
  }

  // 2. 如果没找到值，使用默认值
  if (rawValue === undefined || rawValue === null) {
    rawValue = defaultValue;
  }

  // 3. 执行转换函数 (如果有)
  if (transform && typeof transform === "function") {
    try {
      return transform(rawValue);
    } catch (e) {
      console.warn(`Transform error for key ${sourceKeys.join("/")}:`, e);
      return defaultValue;
    }
  }

  return rawValue;
};

/**
 * 转换 Excel 数据
 */
const convertData = (jsonData: any) => {
  if (!Array.isArray(jsonData)) {
    emit("error", "jsonData 必须是数组");
    return [];
  }

  const result = jsonData.map(row => {
    const newRow: any = {};

    for (const [targetKey, config] of Object.entries(props.mappingConfig)) {
      const fieldConfig = config as ExcelColumnConfig;
      newRow[targetKey] = getValue(row, fieldConfig);
    }

    return newRow;
  });

  return result;
};

/**
 * 加载明细数据
 */
const loadDetailData = async () => {
  if (!props.detailConfig || !form.value?.id) return;

  const { url, paramName, dataPath = "data" } = props.detailConfig;
  loading.value = true;

  try {
    const res = await get(url, { [paramName]: form.value.id });

    // 根据 dataPath 获取数据
    const keys = dataPath.split(".");
    let items = res;
    for (const key of keys) {
      items = items?.[key];
      if (items === undefined || items === null) break;
    }

    form.value[props.itemArrayName] = items || [];
  } catch (error) {
    console.error("加载明细数据失败:", error);
    ElMessage.error("加载明细数据失败");
    form.value[props.itemArrayName] = [];
  } finally {
    loading.value = false;
  }
};

/**
 * 监听 visible 变化
 * 当弹窗打开且是编辑模式（有 id）时，自动加载明细数据
 */
watch(
  () => visible.value,
  newVisible => {
    if (newVisible && props.detailConfig && form.value?.id) {
      // 编辑模式，自动加载明细
      loadDetailData();
    }
  }
);

// 存储当前上传的文件信息，用于显示和移除
const currentFile = ref<UploadUserFile | null>(null);

/**
 * 清空所有数据（文件 + 表格）
 */
const clearAllData = () => {
  // 1. 清空文件引用
  currentFile.value = null;

  // 2. 清空上传组件列表
  uploadRef.value?.clearFiles();

  // 3. 清空表格数据
  if (form.value && Array.isArray(form.value[props.itemArrayName])) {
    form.value[props.itemArrayName].splice(0, form.value[props.itemArrayName].length);
  }

  // 4. 清空验证
  if (baseFormRef.value) {
    baseFormRef.value.clearValidate();
  }
};

/**
 * 处理文件变化
 */
const handleFileChange = (file: any) => {
  // 文件大小校验
  const maxSize = 10 * 1024 * 1024; // 10MB
  if (file.size > maxSize) {
    ElMessage.error("文件大小不能超过 10MB");
    return;
  }

  // 更新当前文件显示
  currentFile.value = file;

  // 解析 Excel（追加模式，不清空原有数据）
  parseExcel(file.raw);
};

/**
 * 解析 Excel 文件
 */
const parseExcel = (file: any) => {
  const reader = new FileReader();

  reader.onload = e => {
    if (!(e.target?.result instanceof ArrayBuffer)) {
      return;
    }
    try {
      const data = new Uint8Array(e.target.result);
      const workbook = XLSX.read(data, { type: "array" });

      // 获取第一个 sheet
      const firstSheetName = workbook.SheetNames[0];
      const worksheet = workbook.Sheets[firstSheetName];

      // 转换为 JSON（保留原始表头映射）
      const jsonData = XLSX.utils.sheet_to_json(worksheet, { defval: "" });

      if (jsonData.length === 0) {
        ElMessage.warning("Excel 文件为空");
        removeFile(); // 清空刚选的文件
        return;
      }

      // 映射字段（支持多种列名）
      const mappedData = convertData(jsonData);

      if (form.value) {
        // 如果 form.value[itemArrayName] 不存在，先初始化为空数组
        if (!Array.isArray(form.value[props.itemArrayName])) {
          form.value[props.itemArrayName] = [];
        }

        // 追加数据到现有数组
        form.value[props.itemArrayName].push(...mappedData);
      }

      ElMessage.success(`解析成功，共追加 ${mappedData.length} 条数据`);

      // 清空上传组件的文件列表，允许用户再次选择文件进行追加
      uploadRef.value?.clearFiles();
      currentFile.value = null;
    } catch (error) {
      console.error(error);
      ElMessage.error("文件解析失败，请检查文件格式");
    }
  };
  reader.readAsArrayBuffer(file);
};

/**
 * 只清理表格数据（保留基本表单数据）
 */
const clearTableData = () => {
  // 1. 清空表格数据
  if (form.value && Array.isArray(form.value[props.itemArrayName])) {
    form.value[props.itemArrayName].splice(0, form.value[props.itemArrayName].length);
  }

  // 2. 清空表单验证（仅表格相关）
  if (baseFormRef.value) {
    baseFormRef.value.clearValidate();
  }

  ElMessage.success("表格数据已清空");
};

/**
 * 深度清理函数（清理表格+文件，保留基本表单数据）
 */
const resetFormData = () => {
  // 1. 清空表格数据
  if (form.value && Array.isArray(form.value[props.itemArrayName])) {
    form.value[props.itemArrayName].splice(0, form.value[props.itemArrayName].length);
  }

  // 2. 清空文件状态
  currentFile.value = null;
  uploadRef.value?.clearFiles();

  // 3. 清空表单验证
  if (baseFormRef.value) {
    baseFormRef.value.clearValidate();
  }
};

/**
 * 增加一行
 */
const addRow = () => {
  if (!form.value) form.value = {};
  if (!Array.isArray(form.value[props.itemArrayName])) {
    form.value[props.itemArrayName] = [];
  }
  // 创建一个空行，根据 mappingConfig 生成默认结构
  const newRow: any = {};
  for (const [key, config] of Object.entries(props.mappingConfig)) {
    const fieldConfig = config as ExcelColumnConfig;
    newRow[key] = fieldConfig.defaultValue !== undefined ? fieldConfig.defaultValue : "";
  }
  form.value[props.itemArrayName].push(newRow);
};

/**
 * 删除指定行
 */
const deleteRow = (index: number) => {
  if (form.value && Array.isArray(form.value[props.itemArrayName])) {
    form.value[props.itemArrayName].splice(index, 1);
  }
};

/**
 * 移除文件
 */
const removeFile = () => {
  clearAllData();
  ElMessage.success("文件已移除，表格数据已清空");
};

/**
 * 获取模板列配置
 * 根据 templateColumns 配置过滤 mappingConfig
 */
const getTemplateColumns = (): [string, ExcelColumnConfig][] => {
  const allEntries = Object.entries(props.mappingConfig) as [string, ExcelColumnConfig][];

  if (!props.templateColumns) {
    return allEntries;
  }

  const { include, exclude } = props.templateColumns;

  if (include && include.length > 0) {
    // 只包含指定的列
    return allEntries.filter(([key]) => include.includes(key));
  }

  if (exclude && exclude.length > 0) {
    // 排除指定的列
    return allEntries.filter(([key]) => !exclude.includes(key));
  }

  return allEntries;
};

/**
 * 下载模板文件
 */
const downloadTemplate = () => {
  // 1. 根据模板列配置生成表头
  const headers: string[] = [];
  const colWidths: { wch: number }[] = [];

  const templateColumns = getTemplateColumns();

  for (const [targetKey, config] of templateColumns) {
    // 使用 header 或 sourceKey 的第一个值作为表头
    const header = getHeaderText(config);
    headers.push(header);

    // 使用配置的列宽，默认 20
    colWidths.push({ wch: config.width || 20 });
  }

  // 2. 创建工作簿
  const wb = XLSX.utils.book_new();

  // 3. 创建工作表（只有表头，没有数据行）
  const ws = XLSX.utils.aoa_to_sheet([headers]);

  // 4. 设置列宽
  ws["!cols"] = colWidths;

  // 5. 将工作表添加到工作簿
  XLSX.utils.book_append_sheet(wb, ws, "模板");

  // 6. 生成文件并下载
  const fileName = `${props.templateFileName}.xlsx`;
  XLSX.writeFile(wb, fileName);

  ElMessage.success("模板文件下载成功");
};

/**
 * 计算属性：确保表格数据始终是一个数组
 */
const tableData = computed(() => {
  if (!form.value) return [];
  const data = form.value[props.itemArrayName];
  return Array.isArray(data) ? data : [];
});

/**
 * 监听 form 变化，确保 itemArrayName 对应的属性是数组
 */
watch(
  () => form.value,
  newVal => {
    if (newVal && !Array.isArray(newVal[props.itemArrayName])) {
      newVal[props.itemArrayName] = [];
    }
  },
  { immediate: true }
);

/**
 * 监听 BaseForm 发出的 reset 事件
 */
const handleBaseFormReset = () => {
  resetFormData();
};

defineExpose({
  innerFormRef: computed(() => baseFormRef.value?.formRef),
  baseFormRef: computed(() => baseFormRef.value?.formRef),
  resetFormData,
  addRow,
  deleteRow,
  clearTableData,
  downloadTemplate,
  loadDetailData,
});
</script>
<template>
  <BaseForm
    ref="baseFormRef"
    v-bind="$attrs"
    class="form-dialog"
    v-model:form="form"
    v-model:visible="visible"
    @reset="handleBaseFormReset"
  >
    <template #form-items>
      <el-divider content-position="left" v-if="props.baseTitle">
        <el-icon><Document /></el-icon>
        {{ props.baseTitle }}
      </el-divider>
      <slot name="form-items"></slot>

      <el-divider content-position="left" v-if="props.tableTitle">
        <el-icon><Document /></el-icon>
        {{ props.tableTitle }}
      </el-divider>

      <el-form-item label="上传 Excel" :prop="`${itemArrayName}`">
        <div class="upload-row">
          <el-upload
            ref="uploadRef"
            class="upload-excel"
            :auto-upload="false"
            :limit="1"
            accept=".xlsx,.xls,.csv"
            :on-change="handleFileChange"
            :show-file-list="false"
          >
            <el-button type="primary" :loading="loading">
              <el-icon><Upload /></el-icon>
              选择 Excel 文件
            </el-button>
            <span class="upload-tip-side">{{ $t("_component.baseFormWithTable.uploadTip") }}</span>
          </el-upload>
          <el-button type="success" @click="downloadTemplate">
            <el-icon><Download /></el-icon>
            下载模板文件
          </el-button>
        </div>
      </el-form-item>

      <el-table
        :data="tableData"
        border
        style="width: 100%"
        max-height="400"
        class="form-item-table"
        v-loading="loading"
      >
        <slot name="form-table-columns"></slot>

        <!-- 固定操作列：删除行 -->
        <el-table-column label="操作" width="80" align="center">
          <template #default="{ $index }">
            <el-button type="danger" link size="small" @click="deleteRow($index)">
              <el-icon><Delete /></el-icon>
            </el-button>
          </template>
        </el-table-column>
      </el-table>

      <!-- 表格下方操作栏 -->
      <div class="table-actions">
        <el-button type="primary" link @click="addRow">
          <el-icon><Plus /></el-icon>
          增加一行
        </el-button>
        <el-button type="warning" link @click="clearTableData">
          <el-icon><Delete /></el-icon>
          清空表格
        </el-button>
      </div>
    </template>
  </BaseForm>
</template>
<style>
.form-dialog {
  --el-dialog-width: fit-content !important;
}

.form-dialog :deep(.el-dialog) {
  overflow: hidden;
  border-radius: 8px;
}

.form-dialog :deep(.el-dialog__header) {
  padding: 16px 20px;
  margin-right: 0;
  background-color: var(--el-fill-color-light);
  border-bottom: 1px solid var(--el-border-color-lighter);
}

.form-dialog :deep(.el-dialog__title) {
  font-size: 16px;
  font-weight: 600;
  color: var(--el-text-color-primary);
}

.form-dialog :deep(.el-dialog__headerbtn) {
  top: 16px;
}

.form-dialog :deep(.el-dialog__body) {
  max-height: 70vh;
  padding: 10px 20px;
  overflow-y: auto;
}

.form-item-table {
  height: 40vh;
}

.upload-row {
  display: flex;
  gap: 12px;
  align-items: center;
  width: 100%;
}

.upload-tip-side {
  margin-left: 4px;
  font-size: 12px;
  line-height: 1.4;
  color: var(--el-text-color-secondary);
  white-space: nowrap;
  opacity: 0.8;
}

.tip-desc {
  font-weight: 500;
  color: var(--el-color-primary);
}

.form-dialog .el-dialog__header {
  padding-bottom: 0;
}

.form-dialog .el-dialog__body {
  padding: 0 !important;
}

.el-dialog {
  --el-dialog-margin-top: 5vh !important;
}

.table-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 5px 0;
  margin-top: 10px;
  text-align: right;
}

.ml-2 {
  margin-left: 8px;
}

.el-icon {
  vertical-align: middle;
}

:deep(.el-divider__text) {
  font-weight: 600;
  color: var(--el-text-color-primary);
}

:deep(.el-divider__text .el-icon) {
  margin-right: 6px;
}

:deep(.el-table) {
  font-size: 13px;
}

:deep(.el-table th.el-table__cell) {
  font-weight: 600;
  background-color: var(--el-fill-color-light);
}

:deep(.el-upload) {
  display: inline-flex;
}

:deep(.el-upload__input) {
  display: none;
}
</style>
