"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getGroupedRowModel = getGroupedRowModel;
/* eslint-disable import/no-cycle -- table-core 内部类型循环，保持现有结构 */
const row_1 = require("../core/row");
const utils_1 = require("../utils");
const grouping_key_1 = require("./grouping-key");
function getGroupedRowModel() {
    return (table) => (0, utils_1.memo)(() => [table.getState().grouping, table.getPreGroupedRowModel()], (grouping, rowModel) => {
        if (!rowModel.rows.length || !grouping.length) {
            rowModel.rows.forEach((row) => {
                row.depth = 0;
                row.parentId = undefined;
            });
            return rowModel;
        }
        // 与「字段管理」隐藏列一致：分组字段可能不在当前 table 列模型中，但仍须按视图分组配置分组（值从 row.original 读取）
        const existingGrouping = grouping.filter(Boolean);
        const groupedFlatRows = [];
        const groupedRowsById = {};
        // const onlyGroupedFlatRows: Row[] = [];
        // const onlyGroupedRowsById: Record<RowId, Row> = {};
        // const nonGroupedFlatRows: Row[] = [];
        // const nonGroupedRowsById: Record<RowId, Row> = {};
        // Recursively group the data
        const groupUpRecursively = (rows, depth = 0, parentId) => {
            // Grouping depth has been been met
            // Stop grouping and simply rewrite thd depth and row relationships
            if (depth >= existingGrouping.length) {
                return rows.map((row) => {
                    row.depth = depth;
                    groupedFlatRows.push(row);
                    groupedRowsById[row.id] = row;
                    if (row.subRows) {
                        row.subRows = groupUpRecursively(row.subRows, depth + 1, row.id);
                    }
                    return row;
                });
            }
            const columnId = existingGrouping[depth];
            // Group the rows together for this level
            const rowGroupsMap = groupBy(table, rows, columnId);
            // Perform aggregations for each group
            const aggregatedGroupedRows = Array.from(rowGroupsMap.entries()).map(([groupingValue, groupedRows], index) => {
                let id = `${columnId}:${groupingValue}`;
                id = parentId ? `${parentId}>${id}` : id;
                // First, Recurse to group sub rows before aggregation
                const subRows = groupUpRecursively(groupedRows, depth + 1, id);
                subRows.forEach((subRow) => {
                    subRow.parentId = id;
                });
                // Flatten the leaf rows of the rows in this group
                const leafRows = depth ? (0, utils_1.flattenBy)(groupedRows, (row) => row.subRows) : groupedRows;
                const row = (0, row_1.createRow)(table, id, leafRows[0].original, index, depth, undefined, parentId);
                Object.assign(row, {
                    groupingColumnId: columnId,
                    groupingValue,
                    subRows,
                    leafRows,
                    getValue: (colId) => {
                        var _a;
                        // Don't aggregate columns that are in the grouping
                        if (existingGrouping.includes(colId)) {
                            if (Object.prototype.hasOwnProperty.call(row._valuesCache, colId)) {
                                return row._valuesCache[colId];
                            }
                            if (groupedRows[0]) {
                                row._valuesCache[colId] =
                                    (_a = getGroupingFieldValue(table, groupedRows[0], colId)) !== null && _a !== void 0 ? _a : undefined;
                            }
                            return row._valuesCache[colId];
                        }
                        if (Object.prototype.hasOwnProperty.call(row._groupingValuesCache, colId)) {
                            return row._groupingValuesCache[colId];
                        }
                        // Aggregate the values
                        const column = table.getColumn(colId);
                        const aggregateFn = column === null || column === void 0 ? void 0 : column.getAggregationFn();
                        if (aggregateFn) {
                            row._groupingValuesCache[colId] = aggregateFn(colId, leafRows, groupedRows);
                            return row._groupingValuesCache[colId];
                        }
                    },
                });
                subRows.forEach((subRow) => {
                    groupedFlatRows.push(subRow);
                    groupedRowsById[subRow.id] = subRow;
                    // if (subRow.getIsGrouped?.()) {
                    //   onlyGroupedFlatRows.push(subRow);
                    //   onlyGroupedRowsById[subRow.id] = subRow;
                    // } else {
                    //   nonGroupedFlatRows.push(subRow);
                    //   nonGroupedRowsById[subRow.id] = subRow;
                    // }
                });
                return row;
            });
            return aggregatedGroupedRows;
        };
        const groupedRows = groupUpRecursively(rowModel.rows, 0);
        groupedRows.forEach((subRow) => {
            groupedFlatRows.push(subRow);
            groupedRowsById[subRow.id] = subRow;
            // if (subRow.getIsGrouped?.()) {
            //   onlyGroupedFlatRows.push(subRow);
            //   onlyGroupedRowsById[subRow.id] = subRow;
            // } else {
            //   nonGroupedFlatRows.push(subRow);
            //   nonGroupedRowsById[subRow.id] = subRow;
            // }
        });
        return {
            rows: groupedRows,
            flatRows: groupedFlatRows,
            rowsById: groupedRowsById,
        };
    }, (0, utils_1.getMemoOptions)(table.options, 'debugTable', 'getGroupedRowModel', () => {
        table._queue(() => {
            table._autoResetExpanded();
            table._autoResetPageIndex();
        });
    }));
}
/** 分组字段可能在「字段管理」中被隐藏而不再出现在 table 列中，此时从 row.original 取键（仅分组模型使用） */
function getGroupingFieldValue(table, row, columnId) {
    if (table.getColumn(columnId)) {
        return row.getGroupingValue(columnId);
    }
    const original = row.original;
    if (original && Object.prototype.hasOwnProperty.call(original, columnId)) {
        return original[columnId];
    }
    return undefined;
}
function groupBy(table, rows, columnId) {
    const groupMap = new Map();
    return rows.reduce((map, row) => {
        const resKey = (0, grouping_key_1.serializeGroupingMapKey)(getGroupingFieldValue(table, row, columnId));
        const previous = map.get(resKey);
        if (!previous) {
            map.set(resKey, [row]);
        }
        else {
            previous.push(row);
        }
        return map;
    }, groupMap);
}
