// exportExcel.ts
import ExcelJS from 'exceljs';

/** ======== 列类型（按需裁剪） ======== */
type AnyCol = {
    title?: any;
    dataIndex?: string | (string | number)[];
    children?: AnyCol[];
    valueEnum?: Record<string | number, { text?: string } | string>;
    renderText?: (text: any, record: any, index: number) => any;
    hideInTable?: boolean;
    valueType?: 'index' | string;
    align?: 'left' | 'center' | 'right';
};

/** ========== 新增：拍平树形数据 ========== */
function flattenTree<T extends Record<string, any>>(
    list: T[] = [],
    childrenKey = 'children',
    out: T[] = []
): T[] {
    for (const node of list) {
        // 先推当前节点（浅拷贝去掉 children，避免把对象树写入单元格）
        const { [childrenKey]: kids, ...rest } = node as any;
        out.push(rest as T);
        if (Array.isArray(kids) && kids.length) {
            flattenTree(kids, childrenKey, out);
        }
    }
    return out;
}

/** 抽取 React 节点文本 */
function extractText(node: any): string {
    if (node == null || node === false) return '';
    if (typeof node === 'string' || typeof node === 'number') return String(node);
    const children = node?.props?.children;
    if (Array.isArray(children)) return children.map(extractText).join('');
    if (children != null) return extractText(children);
    const html = node?.props?.dangerouslySetInnerHTML?.__html;
    if (typeof html === 'string') return html.replace(/<[^>]+>/g, '');
    return String(node ?? '');
}

/** dataIndex 路径取值 */
const toPath = (di?: AnyCol['dataIndex']): (string | number)[] =>
    Array.isArray(di) ? di : (typeof di === 'string' ? di.split('.') : []);
const getByPath = (obj: any, path: (string | number)[]) =>
    path.reduce((acc, k) => (acc == null ? acc : acc[k]), obj);

/** 支持 A|B 或逻辑的取值 */
const getValueWithOr = (obj: any, dataIndex?: AnyCol['dataIndex']): any => {
    if (!dataIndex) return undefined;

    // 如果是数组，直接使用原逻辑
    if (Array.isArray(dataIndex)) {
        return getByPath(obj, dataIndex);
    }

    // 如果是字符串，检查是否包含 | 符号
    if (typeof dataIndex === 'string') {
        if (dataIndex.includes('|')) {
            // 分割并按优先级取值
            const keys = dataIndex.split('|').map(key => key.trim());
            for (const key of keys) {
                const value = getByPath(obj, toPath(key));
                if (value != null && value !== '') {
                    return value;
                }
            }
            return null;
        } else {
            // 普通路径，使用原逻辑
            return getByPath(obj, toPath(dataIndex));
        }
    }

    return undefined;
};

/** 过滤 hideInTable（父级联动） */
function pruneHiddenColumns(cols: AnyCol[]): AnyCol[] {
    const walk = (arr: AnyCol[]): AnyCol[] =>
        (arr || [])
            .filter(col => !col?.hideInTable)
            .map(col => {
                if (col.children?.length) {
                    const kids = walk(col.children);
                    if (!kids.length) return null as any;
                    return { ...col, children: kids };
                }
                return col;
            })
            .filter(Boolean);
    return walk(cols);
}

/** 叶子列（有 dataIndex 的） */
const getLeaves = (cols: AnyCol[]): AnyCol[] => {
    const out: AnyCol[] = [];
    const walk = (arr: AnyCol[]) => {
        arr.forEach(c => {
            if (c?.children?.length) {
                walk(c.children!);
            } else if (c && (c.dataIndex || c.valueType === 'index')) { // << 修改
                out.push(c);
            }
        });
    };
    walk(cols);
    return out;
};

/** 深度和列跨度 */
const getDepth = (cols: AnyCol[]): number => {
    const dfs = (c: AnyCol): number =>
        c.children?.length ? 1 + Math.max(...c.children.map(dfs)) : 1;
    return Math.max(...cols.map(dfs));
};
const getColSpan = (c: AnyCol): number =>
    c.children?.length ? c.children.map(getColSpan).reduce((a, b) => a + b, 0) : 1;

/** 构造多级表头矩阵 & 合并信息（不含顶部大标题/信息行） */
function buildHeaderMatrix(cols: AnyCol[]) {
    const depth = getDepth(cols);
    const rows: string[][] = Array.from({ length: depth }, () => []);
    let colCursor = 0;
    const merges: Array<{ r1: number; c1: number; r2: number; c2: number }> = [];

    const place = (list: AnyCol[], level: number) => {
        list.forEach(col => {
            const span = getColSpan(col);
            const rowSpan = col.children?.length ? 1 : depth - level;
            const title = extractText(col.title ?? '');

            rows[level][colCursor] = title;
            for (let i = 1; i < span; i++) rows[level][colCursor + i] = '';

            if (span > 1 || rowSpan > 1) {
                merges.push({ r1: level + 1, c1: colCursor + 1, r2: level + rowSpan, c2: colCursor + span });
            }

            if (col.children?.length) {
                place(col.children, level + 1);
            } else {
                colCursor += 1;
            }
        });
    };

    place(cols, 0);
    const maxLen = Math.max(...rows.map(r => r.length));
    rows.forEach(r => { for (let i = 0; i < maxLen; i++) if (typeof r[i] === 'undefined') r[i] = ''; });
    return { headerAOA: rows, merges, depth, columnCount: maxLen };
}

/** 单元格显示值（valueEnum / renderText / 原始值） */
function getCellValue(col: AnyCol, record: any, rowIndex: number) {
    // << 新增：序号列
    if (col.valueType === 'index') return rowIndex + 1;

    const raw = getValueWithOr(record, col.dataIndex);
    if (col.valueEnum) {
        const ve = col.valueEnum[raw as any];
        if (typeof ve === 'string') return ve;
        if (ve?.text != null) return ve.text;
    }
    if (col.renderText) {
        try { return col.renderText(raw, record, rowIndex); } catch { }
    }
    return raw;
}

/** 估算列宽（简单） */
const estimateWidth = (v: any) => {
    const s = (v ?? '').toString();
    const len = Array.from(s).reduce((n, ch) => n + (/[^\x00-\xff]/.test(ch) ? 2 : 1), 0);
    return Math.min(Math.max(len + 2, 8), 60);
};

export async function exportXlsxFromProColumnsExcelJS(
    rawColumns: AnyCol[],
    dataSource: any[],
    filename?: string,
    options?: {
        sheetName?: string;
        chunkSize?: number;
        topTitle?: string;
        infoRowLeft?: string;
        infoRowRight?: string;
        freezeHeader?: boolean; // 已保留但默认不再生效（不触发冻结）
        childrenKey?: string;

        // 底部信息
        footerMaker?: any;
        footerMakerTime?: any;
        footerStatsTime?: any;
    }
) {
    const {
        sheetName = '数据',
        chunkSize = 100_000,
        topTitle,
        infoRowLeft,
        infoRowRight,
        // 为兼容外部调用保留字段，但默认不做冻结以满足你的要求
        freezeHeader = false,
        childrenKey = 'children',
        footerMaker,
        footerMakerTime,
        footerStatsTime,
    } = options || {};

    const flatData = flattenTree<any>(Array.isArray(dataSource) ? dataSource : [], childrenKey);

    const columns = pruneHiddenColumns(rawColumns);
    const leafCols = getLeaves(columns);
    if (!leafCols.length) throw new Error('无可导出的列（可能被 hideInTable 全部隐藏）');

    const { headerAOA, merges, columnCount } = buildHeaderMatrix(columns);

    const wb = new ExcelJS.Workbook();
    wb.created = new Date();
    wb.modified = new Date();

    const total = flatData?.length ?? 0;
    const totalSheets = Math.max(1, Math.ceil(total / chunkSize));

    for (let si = 0; si < totalSheets; si++) {
        // 注意：不再传 views 配置，避免任何默认冻结
        const ws = wb.addWorksheet(totalSheets === 1 ? sheetName : `${sheetName}_${si + 1}`);

        let currentRowIndex = 1;

        // 顶部标题
        if (topTitle) {
            const row = ws.getRow(currentRowIndex);
            row.getCell(1).value = topTitle;
            ws.mergeCells(currentRowIndex, 1, currentRowIndex, columnCount);
            const cell = ws.getCell(currentRowIndex, 1);
            cell.alignment = { horizontal: 'center', vertical: 'middle' };
            cell.font = { bold: true, size: 14 };
            row.height = 22;
            currentRowIndex += 1;
        }

        // 信息行
        if (infoRowLeft != null || infoRowRight != null) {
            const row = ws.getRow(currentRowIndex);
            const split = Math.max(1, Math.floor(columnCount / 2));
            if (infoRowLeft != null) {
                row.getCell(1).value = infoRowLeft;
                ws.mergeCells(currentRowIndex, 1, currentRowIndex, split);
                const leftCell = ws.getCell(currentRowIndex, 1);
                leftCell.alignment = { horizontal: 'left', vertical: 'middle' };
                leftCell.font = { size: 11 };
            }
            if (infoRowRight != null) {
                row.getCell(split + 1).value = infoRowRight;
                ws.mergeCells(currentRowIndex, split + 1, currentRowIndex, columnCount);
                const rightCell = ws.getCell(currentRowIndex, split + 1);
                rightCell.alignment = { horizontal: 'right', vertical: 'middle' };
                rightCell.font = { size: 11 };
            }
            row.height = 18;
            currentRowIndex += 1;
        }

        // 表头（保持原有样式与合并）
        const headerStartRow = currentRowIndex;
        headerAOA.forEach((r, idx) => {
            const row = ws.getRow(headerStartRow + idx);
            r.forEach((v, cIdx) => {
                const cell = row.getCell(cIdx + 1);
                cell.value = v;
                cell.alignment = { horizontal: 'center', vertical: 'middle' };
                cell.font = { bold: true };
            });
            row.height = 18;
        });
        merges.forEach(m => {
            ws.mergeCells(headerStartRow + (m.r1 - 1), m.c1, headerStartRow + (m.r2 - 1), m.c2);
        });
        currentRowIndex += headerAOA.length;

        // 数据区
        const start = si * chunkSize;
        const end = Math.min(start + chunkSize, total);
        const batch = flatData.slice(start, end);

        for (let i = 0; i < batch.length; i++) {
            const rec = batch[i];
            const row = ws.getRow(currentRowIndex + i);
            leafCols.forEach((col, j) => {
                const cell = row.getCell(j + 1);
                const v = getCellValue(col, rec, start + i);
                cell.value = v;
                if (col.align) cell.alignment = { horizontal: col.align, vertical: 'middle' };
            });
        }
        currentRowIndex += batch.length;

        // 列宽估算
        const sampleRows = Math.min(batch.length, 200);
        for (let c = 1; c <= columnCount; c++) {
            const headerMax = Math.max(...headerAOA.map(r => estimateWidth(r[c - 1])));
            let dataMax = 8;
            for (let i = 0; i < sampleRows; i++) {
                const v = leafCols[c - 1] ? getCellValue(leafCols[c - 1], batch[i], start + i) : '';
                dataMax = Math.max(dataMax, estimateWidth(v));
            }
            ws.getColumn(c).width = Math.max(headerMax, dataMax);
        }

        // 注意：不再对 ws.views 进行任何设置（避免冻结表头）
        // if (freezeHeader) { ... }  // 已移除

        // 底部三项（同一行 + 平均分列 + 直接显示“标题：值”）
        if (footerMaker != null || footerMakerTime != null || footerStatsTime != null) {
            currentRowIndex += 1;
            const footerRow = ws.getRow(currentRowIndex);

            const items = [
                `制单人员：${footerMaker ?? ''}`,
                `制单时间：${footerMakerTime ?? ''}`,
                `统计时间：${footerStatsTime ?? ''}`,
            ];

            const groups = 3;
            const base = Math.floor(columnCount / groups);
            let remainder = columnCount - base * groups;
            const sizes: number[] = [];
            for (let g = 0; g < groups; g++) {
                sizes.push(base + (remainder > 0 ? 1 : 0));
                if (remainder > 0) remainder -= 1;
            }
            if (columnCount < groups) {
                for (let g = 0; g < groups; g++) sizes[g] = 0;
                for (let k = 0; k < columnCount; k++) sizes[k] = 1;
            }

            let colCursor = 1;
            for (let g = 0; g < groups; g++) {
                const segSize = sizes[g];
                if (segSize <= 0) continue;
                const startCol = colCursor;
                const endCol = colCursor + segSize - 1;

                if (endCol > startCol) ws.mergeCells(currentRowIndex, startCol, currentRowIndex, endCol);

                const cell = footerRow.getCell(startCol);
                cell.value = items[g];
                cell.alignment = { horizontal: 'left', vertical: 'middle' };
                cell.font = { size: 11 };

                colCursor += segSize;
            }

            footerRow.height = 18;
            currentRowIndex += 1;
        }
    }

    // 生成并触发下载
    const buf = await wb.xlsx.writeBuffer();
    const blob = new Blob([buf], {
        type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `${filename || sheetName}.xlsx`;
    a.click();
    setTimeout(() => URL.revokeObjectURL(url), 1000);
}


