import { sortColumnStateForVisibleColumns } from './sortColumnStateForVisibleColumns';
import { isAutoRowGroupColumn } from '../Api/Implementation/ColumnApiImpl';
import { getAutoRowGroupColumnIdFor } from '../Api/Internal/ColumnInternalApi';
import { AG_GRID_GROUPED_COLUMN } from './Constants/GeneralConstants';
import { isPivotLayout } from '../Api/Implementation/LayoutHelpers';
export function buildSortedColumnStateForLayout(params) {
    const { columnState, layout, groupDisplayType } = params;
    const isPivot = isPivotLayout(layout);
    let orderedColumns = isPivot ? layout.PivotColumns : layout.TableColumns;
    const columnVisibilityMap = layout.ColumnVisibility || {};
    const multipleGroupColumns = groupDisplayType === 'multipleColumns';
    const singleGroupColumn = !multipleGroupColumns;
    const rowGroupedColumnsIndexes = {};
    let generatedRowGroupColumnsIds = [];
    const rowGroupedColumns = isPivot ? layout.PivotGroupedColumns : layout.RowGroupedColumns;
    // here we make sure the visibleColumnList includes all the generated group columns
    if (rowGroupedColumns) {
        rowGroupedColumns.forEach((colId, index) => {
            rowGroupedColumnsIndexes[colId] = index;
            rowGroupedColumnsIndexes[getAutoRowGroupColumnIdFor(colId)] = index;
        });
        // if the layout does not include the grouped columns,
        // make sure we add the grouped columns to the visible column list
        // at the start of the list
        if (singleGroupColumn) {
            if (!orderedColumns.includes(AG_GRID_GROUPED_COLUMN)) {
                orderedColumns = [AG_GRID_GROUPED_COLUMN, ...orderedColumns];
            }
            generatedRowGroupColumnsIds.push(AG_GRID_GROUPED_COLUMN);
        }
        else {
            let missingGroupColumns = 0;
            [...rowGroupedColumns].reverse().forEach((colId) => {
                const groupColId = getAutoRowGroupColumnIdFor(colId);
                if (!orderedColumns.includes(groupColId)) {
                    orderedColumns = [groupColId, ...orderedColumns];
                    missingGroupColumns++;
                }
                generatedRowGroupColumnsIds = [groupColId, ...generatedRowGroupColumnsIds];
            });
            // now we need to sort the visibleColumnList to contain the group columns
            // in the correct order
            // but we only need to do this if the layout.Columns list missed some of the
            // group columns, but not all of them. if all were missing, we already
            // inserted them at the start of the list
            if (missingGroupColumns && missingGroupColumns < rowGroupedColumns.length) {
                orderedColumns.sort((colId1, colId2) => {
                    const isRowGroup1 = isAutoRowGroupColumn(colId1);
                    const isRowGroup2 = isAutoRowGroupColumn(colId2);
                    if (isRowGroup1 && isRowGroup2) {
                        return rowGroupedColumnsIndexes[colId1] - rowGroupedColumnsIndexes[colId2];
                    }
                    return 0;
                });
            }
        }
    }
    const pivotMode = isPivot;
    if (pivotMode) {
        // in pivot mode, we sort the Visible columns of the layout
        // to make sure the group cols are at the beginning
        const groupCols = orderedColumns.filter(isAutoRowGroupColumn);
        orderedColumns = orderedColumns.filter((colId) => !isAutoRowGroupColumn(colId));
        orderedColumns = [...groupCols, ...orderedColumns];
    }
    // we're now ready to go over the columnState
    // we want as much as possible to keep the order of the columns
    // as they are in the column state.
    // if the order is different in the visibleColumns, we only move those columns around
    // if some columns in the columnState are not in the visibleColumns, we need to return them as hide: true
    // first step - keep the same order, but filter out old group columns
    // VERY IMPORTANT to only filter out OLD group columns, that is,
    // group columns that are not in the layout anymore
    // since we might have different group columns in the layout
    let newColumnState = [...columnState].filter((colState) => {
        const { colId } = colState;
        if (isAutoRowGroupColumn(colId) && rowGroupedColumnsIndexes[colId] == null) {
            return false;
        }
        return true;
    });
    // second step - keep the same order
    // but make sure the visibility is adjusted to reflect the
    // visible columns in the layout
    newColumnState = newColumnState.map((colState) => {
        const { colId } = colState;
        const hidden = columnVisibilityMap[colId] === false || !orderedColumns.includes(colId);
        if (hidden) {
            return {
                ...colState,
                hide: true,
            };
        }
        return { ...colState, hide: null };
    });
    // third step - correctly mark the columns that are grouped
    newColumnState = newColumnState.map((colState) => {
        const { colId } = colState;
        const groupIndex = rowGroupedColumnsIndexes[colId];
        if (groupIndex != null) {
            return {
                ...colState,
                rowGroup: true,
                rowGroupIndex: groupIndex,
            };
        }
        return {
            ...colState,
            rowGroup: false,
            rowGroupIndex: null,
        };
    });
    // fourth step - add the new group columns, if they are missing
    const columnStateIndexes = newColumnState.reduce((acc, colState, index) => {
        acc[colState.colId] = index;
        return acc;
    }, {});
    generatedRowGroupColumnsIds.reverse().forEach((rowGroupColId) => {
        if (columnStateIndexes[rowGroupColId] == null) {
            newColumnState = [
                {
                    colId: rowGroupColId,
                },
                ...newColumnState,
            ];
        }
    });
    // fitfth step - sort the column state to respect the order of the visible columns
    // we can't simply call sort in this case
    return sortColumnStateForVisibleColumns(newColumnState, orderedColumns);
}
