/**
 * ============================================================
 * csv-parser.ts — CSV 文件解析模块
 * ============================================================
 * 功能：
 *   1. parseCsvBuffer()  — 从 Buffer 解析 CSV，返回 RawCsvRow[]
 *   2. parseCsvFile()    — 从文件路径解析 CSV，返回 RawCsvRow[]
 * 
 * 使用 xlsx 库（项目已安装）解析 CSV，自动处理编码和分隔符。
 * 将中文表头映射到 RawCsvRow 类型的字段。
 * ============================================================
 */

import { readFileSync } from "node:fs";
import XLSX from "xlsx";
import type { RawCsvRow } from "./types.ts";

// ── 中文表头 → RawCsvRow 字段名的映射表 ──────────────────────
// 支持多种可能的表头写法（去空格后匹配）
const HEADER_MAP: Record<string, keyof RawCsvRow> = {
  发票种类: "发票种类",
  名称: "名称",
  规格型号: "规格型号",
  品牌: "品牌",
  数量: "数量",
  单位: "单位",
  "备注/附件": "备注/附件",
  备注: "备注/附件",
  附件: "备注/附件",
  收货地址: "收货地址",
};

/**
 * 将表头文本标准化（去除前后空格和不可见字符）
 */
function normalizeHeader(header: string): string {
  return header.replace(/[\s\u00A0\uFEFF]/g, "").trim();
}

/**
 * 将 xlsx 解析出的原始对象行，按表头映射为标准 RawCsvRow
 * @param rawObj - xlsx 解析出的 key-value 对象
 * @param headerMapping - 实际表头 → RawCsvRow 字段名的映射
 * @returns 标准化的 RawCsvRow
 */
function mapToRawCsvRow(
  rawObj: Record<string, unknown>,
  headerMapping: Map<string, keyof RawCsvRow>,
): RawCsvRow {
  // 初始化默认空值
  const row: RawCsvRow = {
    发票种类: "",
    名称: "",
    规格型号: "",
    品牌: "",
    数量: "",
    单位: "",
    "备注/附件": "",
    收货地址: "",
  };

  // 遍历原始对象的每个字段，按映射表填入标准字段
  for (const [originalHeader, value] of Object.entries(rawObj)) {
    const normalized = normalizeHeader(originalHeader);
    const targetKey = headerMapping.get(normalized);
    if (targetKey) {
      row[targetKey] = String(value ?? "").trim();
    }
  }

  return row;
}

/**
 * 从 Buffer 解析 CSV 文件内容，返回标准化的 RawCsvRow 数组
 * @param buffer - CSV 文件的 Buffer 内容
 * @returns 解析后的行数组（不含表头行）
 */
export function parseCsvBuffer(buffer: Buffer): RawCsvRow[] {
  // 使用 xlsx 读取 Buffer
  const workbook = XLSX.read(buffer, { type: "buffer" });
  // 取第一个工作表
  const sheetName = workbook.SheetNames[0];
  if (!sheetName) throw new Error("CSV 文件为空，找不到工作表");
  const sheet = workbook.Sheets[sheetName];
  if (!sheet) throw new Error("CSV 文件工作表为空");

  // 解析为 JSON 数组（每行是 { 表头: 值 } 的对象）
  const rawRows = XLSX.utils.sheet_to_json<Record<string, unknown>>(sheet, {
    defval: "", // 缺失单元格填空字符串
  });

  if (rawRows.length === 0) throw new Error("CSV 文件没有数据行");

  // 构建实际表头 → RawCsvRow 字段名的映射
  const firstRow = rawRows[0]!;
  const headerMapping = new Map<string, keyof RawCsvRow>();
  for (const originalHeader of Object.keys(firstRow)) {
    const normalized = normalizeHeader(originalHeader);
    const mapped = HEADER_MAP[normalized];
    if (mapped) {
      headerMapping.set(normalized, mapped);
    }
  }

  // 检查是否至少映射到了「名称」字段（最关键的字段）
  const hasMandatory = [...headerMapping.values()].includes("名称");
  if (!hasMandatory) {
    throw new Error(
      `CSV 表头中找不到「名称」字段。检测到的表头：${Object.keys(firstRow).join(", ")}`,
    );
  }

  // 将每行映射为标准 RawCsvRow
  return rawRows.map((raw) => mapToRawCsvRow(raw, headerMapping));
}

/**
 * 从文件路径读取 CSV 并解析
 * @param filePath - CSV 文件的绝对或相对路径
 * @returns 解析后的行数组
 */
export function parseCsvFile(filePath: string): RawCsvRow[] {
  const buffer = readFileSync(filePath);
  return parseCsvBuffer(buffer);
}
