/**
 * SmartExcelUpload — 템플릿 생성기
 * ExcelJS 기반: 드롭다운, VLOOKUP 수식, INDIRECT 동적 드롭다운,
 * 참조시트, 조건부서식, _meta 해시시트
 */

import ExcelJS from "exceljs";
import type {
  SmartExcelUploadConfig,
  ItemProcessMapping,
} from "./types";

/** 카테고리 값들로 해시 생성 */
function generateHash(data: string): string {
  let hash = 0;
  for (let i = 0; i < data.length; i++) {
    const char = data.charCodeAt(i);
    hash = ((hash << 5) - hash + char) | 0;
  }
  return Math.abs(hash).toString(36);
}

/** 엑셀 컬럼 문자 (1→A, 2→B, ..., 27→AA) */
function colLetter(index: number): string {
  let result = "";
  let n = index;
  while (n > 0) {
    n--;
    result = String.fromCharCode(65 + (n % 26)) + result;
    n = Math.floor(n / 26);
  }
  return result;
}

/** 품목코드를 엑셀 이름 범위에 사용 가능한 이름으로 변환 */
function sanitizeNameForExcel(itemCode: string): string {
  // 엑셀 이름 범위 규칙: 문자/밑줄로 시작, 영숫자/밑줄만 허용
  return "P_" + itemCode.replace(/[^a-zA-Z0-9]/g, "_");
}

export interface GenerateTemplateOptions {
  config: SmartExcelUploadConfig;
  /** 참조시트 데이터 (DB에서 조회한 검사기준 등) */
  referenceData?: Record<string, any>[];
  /** 시트별 드롭다운 옵션 (카테고리 값 등) */
  dropdownOptions?: Record<string, string[]>;
  /** 품목별 공정 매핑 (INDIRECT 동적 드롭다운용) */
  itemProcessMappings?: ItemProcessMapping[];
  /** 추가 메타 정보 */
  extraMeta?: Record<string, string>;
}

export async function generateTemplate(
  options: GenerateTemplateOptions
): Promise<ExcelJS.Buffer> {
  const { config, referenceData, dropdownOptions, itemProcessMappings, extraMeta } = options;

  const workbook = new ExcelJS.Workbook();
  workbook.creator = "WACE ERP";
  workbook.created = new Date();

  // 해시 소스: 참조 데이터 + 드롭다운 옵션 + 품목공정매핑
  const hashSource = JSON.stringify({
    referenceData,
    dropdownOptions,
    itemProcessMappings: itemProcessMappings?.map(m => ({
      itemCode: m.itemCode,
      processes: m.processes.map(p => p.name),
    })),
  });
  const versionHash = generateHash(hashSource);

  // ═══════════════════ 1. 참조시트 생성 ═══════════════════
  let refSheet: ExcelJS.Worksheet | null = null;
  const refDataRows = referenceData || config.referenceSheet?.data || [];
  const refCols = config.referenceSheet?.columns || [];

  if (config.referenceSheet && refCols.length > 0) {
    refSheet = workbook.addWorksheet(config.referenceSheet.name, {
      state: "veryHidden",
    });

    // 헤더
    const headerRow = refSheet.addRow(refCols.map((c) => c.label));
    headerRow.eachCell((cell) => {
      cell.font = { bold: true, size: 10 };
      cell.fill = { type: "pattern", pattern: "solid", fgColor: { argb: "FFE2E8F0" } };
      cell.border = { bottom: { style: "thin", color: { argb: "FF94A3B8" } } };
    });

    for (const row of refDataRows) {
      refSheet.addRow(refCols.map((c) => row[c.key] ?? ""));
    }

    refCols.forEach((_, i) => { refSheet!.getColumn(i + 1).width = 20; });
  }

  // ═══════════════════ 1-B. 합격기준 옵션 시트 (INDIRECT용) ═══════════════════
  // 검사기준별 판단기준에 따라 합격기준 드롭다운을 동적으로 변경
  // 한글은 엑셀 이름 범위에 사용 불가 → 숫자 인덱스 ACC_1, ACC_2... 사용
  // INDIRECT("ACC_" & MATCH(검사기준셀, 검사기준정보!A열, 0)) 방식
  // ═══════════════════ 1-B. INDIRECT ACC_ 동적 드롭다운 옵션 시트 ═══════════════════
  const hasAccPrefix = config.sheets.some(s => s.columns.some(c => c.dropdown?.indirectPrefix === "ACC_"));
  if (refDataRows.length > 0 && hasAccPrefix && config.indirectOptions) {
    const accSheet = workbook.addWorksheet("_합격기준옵션", { state: "veryHidden" });
    const { conditionColumn, optionsByCondition, selectionOptionsColumn } = config.indirectOptions;

    for (let i = 0; i < refDataRows.length; i++) {
      const row = refDataRows[i];
      const condValue = row[conditionColumn] || "";
      const rowNum = i + 1;
      const safeName = `ACC_${rowNum}`;

      // 조건값에 매칭되는 고정 옵션 확인
      let options: string[] = optionsByCondition[condValue] || [];

      // 선택옵션 컬럼에서 동적으로 가져오기 (콤마 구분)
      if (options.length === 0 && selectionOptionsColumn) {
        const selOpts = row[selectionOptionsColumn] || "";
        if (selOpts) {
          options = selOpts.split(",").map((s: string) => s.trim()).filter(Boolean);
        }
      }

      if (options.length > 0) {
        for (let j = 0; j < options.length; j++) {
          accSheet.getCell(`${colLetter(j + 1)}${rowNum}`).value = options[j];
        }
        const endCol = colLetter(options.length);
        try {
          workbook.definedNames.add(`'_합격기준옵션'!$A$${rowNum}:$${endCol}$${rowNum}`, safeName);
        } catch { /* skip */ }
      }
      // 매칭 안 되면 이름 범위 미등록 → INDIRECT 실패 → 자유 입력
    }
  }

  // ═══════════════════ 2. 품목공정 매핑 시트 (INDIRECT용) ═══════════════════
  const hasItemProcess = itemProcessMappings && itemProcessMappings.length > 0;
  if (hasItemProcess) {
    const procSheet = workbook.addWorksheet("_품목공정", { state: "veryHidden" });
    procSheet.getColumn(1).width = 20;

    // 품목별로 열에 공정 목록 배치, 이름 범위 등록
    // 방식: 각 품목코드를 열 방향으로 배치 (A열: 품목1 공정들, B열: 품목2 공정들...)
    // → 이름 범위 수가 너무 많아질 수 있으므로, 행 방향으로 배치
    // 방식 변경: 품목코드를 A열, 공정을 B열~에 넣고, 이름 범위로 등록
    // → ExcelJS는 definedNames 지원

    for (let i = 0; i < itemProcessMappings!.length; i++) {
      const mapping = itemProcessMappings![i];
      const safeName = sanitizeNameForExcel(mapping.itemCode);
      const rowNum = i + 1;

      // A열: 품목코드 (참조용)
      procSheet.getCell(`A${rowNum}`).value = mapping.itemCode;

      // B열~: 공정명들
      const procs = mapping.processes;
      if (procs.length > 0) {
        for (let j = 0; j < procs.length; j++) {
          procSheet.getCell(`${colLetter(j + 2)}${rowNum}`).value = procs[j].name;
        }
        // 이름 범위 등록: add(rangeString, name)
        const startCol = colLetter(2); // B
        const endCol = colLetter(procs.length + 1);
        workbook.definedNames.add(`'_품목공정'!$${startCol}$${rowNum}:$${endCol}$${rowNum}`, safeName);
      }
      // 공정 없는 품목: 이름 범위 미등록 → INDIRECT 실패 → 드롭다운 안 뜸 (자유 입력)
    }

    // 품목코드 목록도 별도 시트에 (드롭다운용)
    const itemListSheet = workbook.addWorksheet("_품목목록", { state: "veryHidden" });
    itemProcessMappings!.forEach((m, i) => {
      itemListSheet.getCell(`A${i + 1}`).value = m.itemCode;
      itemListSheet.getCell(`B${i + 1}`).value = m.itemName;
    });
  }

  // ═══════════════════ 3. 검사시트별 생성 ═══════════════════
  for (const sheetConfig of config.sheets) {
    const ws = workbook.addWorksheet(sheetConfig.name);

    // 컬럼 너비
    sheetConfig.columns.forEach((col, i) => {
      ws.getColumn(i + 1).width = col.width || 18;
    });

    // 헤더 행
    const headerRow = ws.addRow(sheetConfig.columns.map((c) => c.label));
    headerRow.height = 28;
    headerRow.eachCell((cell, colNumber) => {
      const col = sheetConfig.columns[colNumber - 1];
      cell.font = { bold: true, size: 10, color: { argb: "FF1E293B" } };
      cell.fill = { type: "pattern", pattern: "solid", fgColor: { argb: "FFF1F5F9" } };
      cell.border = { bottom: { style: "medium", color: { argb: "FF94A3B8" } } };
      cell.alignment = { vertical: "middle", horizontal: "center" };

      if (col?.required) {
        cell.font = { bold: true, size: 10, color: { argb: "FFDC2626" } };
      }
      if (col?.readOnly || col?.autoFill) {
        cell.fill = { type: "pattern", pattern: "solid", fgColor: { argb: "FFE2E8F0" } };
      }
    });

    // ═══════ 컬럼 범위 기반 data validation + 수식 (행 제한 없음) ═══════
    // 행 2부터 10000까지 범위 설정 (셀 루프 대신 범위 단위)
    // 수식 행 수: 성능과 사용성 균형 (드롭다운 validation은 범위라 무제한)
    const FORMULA_END = 2000;
    const VALIDATION_END = 65000;

    for (let colIdx = 0; colIdx < sheetConfig.columns.length; colIdx++) {
      const col = sheetConfig.columns[colIdx];
      const colL = colLetter(colIdx + 1);
      const rangeStr = `${colL}2:${colL}${VALIDATION_END}`;

      // ── 수식 컬럼: 2행에만 수식 세팅 (사용자가 아래로 복사하거나 테이블 확장) ──
      if (col.customFormula) {
        let formula = col.customFormula;
        formula = formula.replace(/\{col:(\w+)\}/g, (_, key) => {
          const idx = sheetConfig.columns.findIndex(c => c.key === key);
          return idx >= 0 ? `${colLetter(idx + 1)}2` : `"?"`;
        });
        formula = formula.replace(/\{itemCount\}/g, String(itemProcessMappings?.length || 9999));
        // 2행~FORMULA_END 행에 수식 삽입 (잠금 + 회색 배경)
        for (let r = 2; r <= FORMULA_END; r++) {
          // 상대참조만 치환 (A2→A{r}), 절대참조($A$2)는 유지
          const rowFormula = formula.replace(/(?<!\$)([A-Z]+)(?<!\$)2(?![0-9])/g, (match, c) => `${c}${r}`);
          const cell = ws.getCell(`${colL}${r}`);
          cell.value = { formula: rowFormula } as any;
          cell.protection = { locked: true };
          cell.fill = { type: "pattern", pattern: "solid", fgColor: { argb: "FFF8FAFC" } };
          cell.font = { size: 10, color: { argb: "FF64748B" } };
          cell.border = { top: { style: "hair", color: { argb: "FFE2E8F0" } }, bottom: { style: "hair", color: { argb: "FFE2E8F0" } }, left: { style: "hair", color: { argb: "FFE2E8F0" } }, right: { style: "hair", color: { argb: "FFE2E8F0" } } };
        }
        continue;
      }

      if (col.autoFill && refSheet && refCols.length > 0) {
        const lookupColIdx = sheetConfig.columns.findIndex(c => c.key === col.autoFill!.lookupColumn);
        const refColIdx = refCols.findIndex(c => c.key === col.autoFill!.referenceColumn) + 1;
        if (lookupColIdx >= 0 && refColIdx > 0) {
          const refRange = `'${config.referenceSheet!.name}'!$A$2:$${colLetter(refCols.length)}$${refDataRows.length + 1}`;
          for (let r = 2; r <= FORMULA_END; r++) {
            const lookupCell = `${colLetter(lookupColIdx + 1)}${r}`;
            const cell = ws.getCell(`${colL}${r}`);
            cell.value = { formula: `IFERROR(VLOOKUP(${lookupCell},${refRange},${refColIdx},FALSE),"")` } as any;
            cell.protection = { locked: true };
            cell.fill = { type: "pattern", pattern: "solid", fgColor: { argb: "FFF8FAFC" } };
            cell.font = { size: 10, color: { argb: "FF64748B" } };
            cell.border = { top: { style: "hair", color: { argb: "FFE2E8F0" } }, bottom: { style: "hair", color: { argb: "FFE2E8F0" } }, left: { style: "hair", color: { argb: "FFE2E8F0" } }, right: { style: "hair", color: { argb: "FFE2E8F0" } } };
          }
        }
        continue;
      }

      // ── data validation: 범위 단위로 한 번에 설정 ──
      // enableWhen (참조시트 직접 조회)
      if (col.enableWhen && refSheet && refCols.length > 0 && refDataRows.length > 0) {
        const condRefColIdx = refCols.findIndex(c => c.key === col.enableWhen!.column);
        const lookupKeyColIdx = sheetConfig.columns.findIndex(c => c.autoFill?.referenceColumn === col.enableWhen!.column);
        const lookupSourceColIdx = lookupKeyColIdx >= 0
          ? sheetConfig.columns.findIndex(c => c.key === sheetConfig.columns[lookupKeyColIdx].autoFill?.lookupColumn)
          : -1;

        if (condRefColIdx >= 0 && lookupSourceColIdx >= 0) {
          const lookupColL = colLetter(lookupSourceColIdx + 1);
          const refRange = `'${config.referenceSheet!.name}'!$A$2:$A$${refDataRows.length + 1}`;
          const refValueRange = `'${config.referenceSheet!.name}'!$${colLetter(condRefColIdx + 1)}$2:$${colLetter(condRefColIdx + 1)}$${refDataRows.length + 1}`;
          const keyword = col.enableWhen.equals.replace(/[()]/g, "").slice(0, 2);
          const condColLabel = sheetConfig.columns.find(c => c.key === col.enableWhen!.column)?.label || col.enableWhen!.column;

          // 상대 참조 (2행 기준, 범위 적용 시 자동 조정)
          (ws as any).dataValidations.add(rangeStr, {
            type: "custom",
            allowBlank: true,
            formulae: [`ISNUMBER(SEARCH("${keyword}",IFERROR(INDEX(${refValueRange},MATCH(${lookupColL}2,${refRange},0)),"")))`],
            showErrorMessage: true,
            errorStyle: "stop",
            errorTitle: "입력 불가",
            error: `${condColLabel}이(가) "${col.enableWhen.equals}"일 때만 입력 가능합니다`,
          });
        }
        continue;
      }

      // INDIRECT 동적 드롭다운
      if (col.dropdown?.source === "indirect") {
        const prefix = col.dropdown.indirectPrefix || "P_";
        const keyColName = col.dropdown.indirectKeyColumn;
        if (!keyColName) continue;
        const keyColIdx = sheetConfig.columns.findIndex(c => c.key === keyColName);

        if (keyColIdx >= 0) {
          const keyColL = colLetter(keyColIdx + 1);
          if (prefix === "ACC_" && refDataRows.length > 0) {
            const refNameRange = `'${config.referenceSheet!.name}'!$A$2:$A$${refDataRows.length + 1}`;
            (ws as any).dataValidations.add(rangeStr, {
              type: "list",
              allowBlank: true,
              formulae: [`INDIRECT("ACC_"&MATCH(${keyColL}2,${refNameRange},0))`],
              showErrorMessage: false,
            });
          } else {
            // sanitizeNameForExcel과 동일한 치환: 비영숫자 → _
            const sanitizeFormula = `SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(${keyColL}2,"-","_"),".","_")," ","_"),"/","_"),"(","_"),")","_"),"#","_")`;
            (ws as any).dataValidations.add(rangeStr, {
              type: "list",
              allowBlank: true,
              formulae: [`INDIRECT("${prefix}"&${sanitizeFormula})`],
              showErrorMessage: false,
            });
          }
        }
        continue;
      }

      // 일반 드롭다운
      if (col.type === "dropdown") {
        const optionKey = `${sheetConfig.name}:${col.key}`;
        const globalKey = col.key;
        const configValues = col.dropdown?.values;
        const values =
          (configValues && configValues.length > 0 ? configValues : null) ||
          dropdownOptions?.[optionKey] ||
          dropdownOptions?.[globalKey] ||
          [];

        if (values.length > 0) {
          // 품목목록 시트 참조 (품목명 등 대량 드롭다운)
          const isItemNameDropdown = hasItemProcess && values.length === itemProcessMappings!.length
            && values[0] === itemProcessMappings![0]?.itemName;
          if (isItemNameDropdown) {
            (ws as any).dataValidations.add(rangeStr, {
              type: "list",
              allowBlank: !col.required,
              formulae: [`'_품목목록'!$B$1:$B$${itemProcessMappings!.length}`],
              showErrorMessage: true,
              errorStyle: "stop",
              errorTitle: "입력 오류",
              error: "품목 목록에서 선택해주세요",
            });
          } else {
            const joined = `"${values.join(",")}"`;
            if (joined.length <= 255) {
              (ws as any).dataValidations.add(rangeStr, {
                type: "list",
                allowBlank: !col.required,
                formulae: [joined],
                showErrorMessage: true,
              errorStyle: "stop",
                errorTitle: "입력 오류",
                error: `다음 중 선택: ${values.slice(0, 5).join(", ")}${values.length > 5 ? " ..." : ""}`,
              });
            } else {
              const listSheetName = `_list_${sheetConfig.name}_${col.key}`.slice(0, 31);
              let listSheet = workbook.getWorksheet(listSheetName);
              if (!listSheet) {
                listSheet = workbook.addWorksheet(listSheetName, { state: "veryHidden" });
                values.forEach((v, i) => { listSheet!.getCell(`A${i + 1}`).value = v; });
              }
              (ws as any).dataValidations.add(rangeStr, {
                type: "list",
                allowBlank: !col.required,
                formulae: [`'${listSheetName}'!$A$1:$A$${values.length}`],
                showErrorMessage: true,
              errorStyle: "stop",
                errorTitle: "입력 오류",
                error: "목록에서 선택해주세요",
              });
            }
          }
        }
        continue;
      }

      // 숫자 포맷
      if (col.type === "number") {
        ws.getColumn(colIdx + 1).numFmt = "#,##0.##";
      }
    }

    // 시트 보호 — 수식/자동입력 컬럼 잠금, 편집 컬럼 해제
    const hasLockedCols = sheetConfig.columns.some(c => c.autoFill || c.readOnly || c.customFormula);
    if (hasLockedCols) {
      // Excel 기본: 모든 셀 locked=true → 편집 가능 컬럼만 unlocked 처리
      const editableColIndices: number[] = [];
      sheetConfig.columns.forEach((c, ci) => {
        if (!c.autoFill && !c.readOnly && !c.customFormula) {
          editableColIndices.push(ci);
        }
      });
      // 편집 가능 컬럼만 unlock (FORMULA_END 행까지)
      for (const ci of editableColIndices) {
        const cl = colLetter(ci + 1);
        for (let r = 2; r <= FORMULA_END; r++) {
          const editCell = ws.getCell(`${cl}${r}`);
          editCell.protection = { locked: false };
          editCell.border = { top: { style: "hair", color: { argb: "FFE2E8F0" } }, bottom: { style: "hair", color: { argb: "FFE2E8F0" } }, left: { style: "hair", color: { argb: "FFE2E8F0" } }, right: { style: "hair", color: { argb: "FFE2E8F0" } } };
        }
      }
      ws.protect("", {
        selectLockedCells: true,
        selectUnlockedCells: true,
        formatCells: true,
        sort: true,
        autoFilter: true,
      });
    }

    // 고정틀
    ws.views = [{ state: "frozen", ySplit: 1, xSplit: 0 }];
  }

  // ═══════════════════ 4. 안내 시트 ═══════════════════
  const guideSheet = workbook.addWorksheet("안내");
  guideSheet.getColumn(1).width = 20;
  guideSheet.getColumn(2).width = 50;

  // Config 기반으로 안내시트 자동 생성
  const firstSheetCols = config.sheets[0]?.columns || [];
  const lockedCols = firstSheetCols.filter(c => c.autoFill || c.readOnly || c.customFormula).map(c => c.label);
  const editableCols = firstSheetCols.filter(c => !c.autoFill && !c.readOnly && !c.customFormula);

  const guideData: [string, string][] = [
    ["템플릿 정보", ""],
    ["파일명", config.templateName],
    ["생성일시", new Date().toLocaleString("ko-KR")],
    ...(hasItemProcess ? [["품목 수", `${itemProcessMappings!.length}건`] as [string, string]] : []),
    ["시트 구성", config.sheets.map(s => s.name).join(", ")],
    ["", ""],
    ["컬럼 설명", ""],
    // 컬럼별 자동 설명 생성
    ...firstSheetCols.map((col): [string, string] => {
      const parts: string[] = [];
      if (col.required) parts.push("필수");
      if (col.autoFill) parts.push(`${firstSheetCols.find(c => c.key === col.autoFill!.lookupColumn)?.label || ""} 선택 시 자동 입력 (수정 불가)`);
      else if (col.customFormula) parts.push("자동 입력 (수정 불가)");
      else if (col.readOnly) parts.push("읽기전용");
      else if (col.dropdown?.source === "indirect") parts.push("연동 드롭다운 (관련 컬럼 선택 후 목록 표시)");
      else if (col.type === "dropdown") parts.push("드롭다운에서 선택");
      else if (col.type === "number") parts.push("숫자 입력");
      else parts.push("텍스트 입력");
      if (col.enableWhen) parts.push(`${firstSheetCols.find(c => c.key === col.enableWhen!.column)?.label || col.enableWhen!.column}이(가) "${col.enableWhen.equals}"일 때만 입력 가능`);
      return [col.label, parts.join(" — ")];
    }),
    ["", ""],
    // 조건부 규칙이 있으면 자동 설명
    ...(config.conditionalRules && config.conditionalRules.length > 0 ? [
      ["조건별 입력 규칙", ""] as [string, string],
      ...config.conditionalRules.map((rule): [string, string] => {
        const reqLabels = rule.require.map(k => firstSheetCols.find(c => c.key === k)?.label || k).join(", ");
        const ignLabels = rule.ignore.map(k => firstSheetCols.find(c => c.key === k)?.label || k).join(", ");
        const condLabel = firstSheetCols.find(c => c.key === rule.when.column)?.label || rule.when.column;
        return [rule.when.equals, `${condLabel}이(가) "${rule.when.equals}"일 때: ${reqLabels} 필수${ignLabels ? `, ${ignLabels} 무시` : ""}`];
      }),
      ["", ""] as [string, string],
    ] : []),
    ["사용 방법", ""],
    ["1단계", `하단의 시트(${config.sheets.map(s => s.name).join(", ")})로 이동`],
    ...editableCols.slice(0, 3).map((col, i): [string, string] =>
      [`${i + 2}단계`, `${col.label}${col.type === "dropdown" ? "을(를) 드롭다운에서 선택" : "을(를) 입력"}`]
    ),
    [`${Math.min(editableCols.length, 3) + 2}단계`, "필요한 시트만 작성 (사용하지 않는 시트는 비워두세요)"],
    [`${Math.min(editableCols.length, 3) + 3}단계`, "작성 완료 후 시스템에서 파일 업로드"],
    ["", ""],
    ["주의사항", ""],
    ...(lockedCols.length > 0 ? [[
      "1", `잠금된 셀(${lockedCols.join(", ")})은 자동 입력됩니다. 직접 수정하지 마세요.`
    ] as [string, string]] : []),
    ["2", "사용하지 않는 시트는 비워두면 자동으로 무시됩니다."],
    ["3", "기준 데이터가 변경된 경우 템플릿을 다시 다운로드해주세요."],
    ["4", "업로드 시 입력 데이터를 자동 검증합니다. 오류가 있으면 상세 내용이 표시됩니다."],
  ];

  guideData.forEach(([a, b]) => {
    const row = guideSheet.addRow([a, b]);
    if (["템플릿 정보", "컬럼 설명", "사용 방법", "조건별 입력 규칙", "주의사항"].includes(a)) {
      row.eachCell((cell) => {
        cell.font = { bold: true, size: 12, color: { argb: "FF1E40AF" } };
      });
    }
  });

  // ═══════════════════ 5. _meta 시트 (숨김) ═══════════════════
  const metaSheet = workbook.addWorksheet("_meta", { state: "veryHidden" });
  metaSheet.getColumn(1).width = 20;
  metaSheet.getColumn(2).width = 50;

  const metaEntries: [string, string][] = [
    ["version_hash", versionHash],
    ["created_at", new Date().toISOString()],
    ["template_name", config.templateName],
    ["item_count", hasItemProcess ? String(itemProcessMappings!.length) : "0"],
    ...(Object.entries(extraMeta || {}) as [string, string][]),
    ...(Object.entries(config.extraMeta || {}) as [string, string][]),
  ];
  metaEntries.forEach(([k, v]) => metaSheet.addRow([k, v]));

  // ═══════════════════ 6. 시트 순서 조정 ═══════════════════
  const guideIdx = workbook.worksheets.findIndex((ws) => ws.name === "안내");
  if (guideIdx > 0) {
    (guideSheet as any).orderNo = 0;
    let order = 1;
    for (const ws of workbook.worksheets) {
      if (ws.name !== "안내") {
        (ws as any).orderNo = order++;
      }
    }
  }

  const buffer = await workbook.xlsx.writeBuffer();
  return buffer;
}

/** 현재 DB 데이터 기반 해시 재생성 (업로드 검증용) */
export function regenerateHash(
  referenceData: Record<string, any>[],
  dropdownOptions: Record<string, string[]>,
  itemProcessMappings?: ItemProcessMapping[]
): string {
  const hashSource = JSON.stringify({
    referenceData,
    dropdownOptions,
    itemProcessMappings: itemProcessMappings?.map(m => ({
      itemCode: m.itemCode,
      processes: m.processes.map(p => p.name),
    })),
  });
  return generateHash(hashSource);
}
