import { ColumnFilterModuleId, GridFilterModuleId, } from '../../Utilities/Constants/ModuleConstants';
import ArrayExtensions from '../../Utilities/Extensions/ArrayExtensions';
import { ApiBase } from '../Implementation/ApiBase';
import { areLayoutsEqual, normalizeLayout } from '../Implementation/LayoutHelpers';
export class LayoutInternalApi extends ApiBase {
    getNormalizedLayout(layout) {
        return normalizeLayout(layout);
    }
    sortColumnDefsByPivotAggregationOrder(columnDefs, pivotAggregationColumns) {
        if (!pivotAggregationColumns.length) {
            return columnDefs;
        }
        let sortPivotAggColsToIndexes = null;
        let sortPivotAggColsIndexToColId = null;
        // because aggrid does not respect the aggregation order provided by the layout
        // we have to sort the coldefs
        // see the test at #keep-initial-aggregation-order
        sortPivotAggColsIndexToColId = {};
        sortPivotAggColsToIndexes = pivotAggregationColumns.reduce((acc, colDef, index) => {
            acc[colDef.ColumnId] = index;
            sortPivotAggColsIndexToColId[index] = colDef.ColumnId;
            return acc;
        }, {});
        let currentColIndex = 0;
        const colIdsToIndexes = {};
        function colIdToIndex(colDef) {
            if (colDef.children) {
                colDef.children.forEach(colIdToIndex);
            }
            else {
                colIdsToIndexes[colDef.colId] = currentColIndex;
                currentColIndex++;
            }
        }
        columnDefs.forEach(colIdToIndex);
        const initialColIdsToIndexes = { ...colIdsToIndexes };
        let currentAggIndex = 0;
        Object.keys(colIdsToIndexes).forEach((colId) => {
            if (sortPivotAggColsToIndexes[colId] !== undefined) {
                // this column is used in aggregation
                // assume we have cols: a,b,X,c,Y - X and Y are used in the pivot aggregation - but the agg order is Y,X
                // so the current indexes are 0 1 2 3 4 - but we should have
                // 0 1 4 2 3 - because we want to swap X and Y so they are in the order in which they are used in the pivot aggregation
                const columnAtCurrentAggIndex = sortPivotAggColsIndexToColId[currentAggIndex];
                const newIndex = initialColIdsToIndexes[columnAtCurrentAggIndex];
                colIdsToIndexes[colId] = newIndex;
                currentAggIndex++;
            }
        });
        const sortFn = (colDefA, colDefB) => {
            if (colDefA.children || colDefB.children) {
                if (colDefA.children) {
                    colDefA.children.sort(sortFn);
                }
                if (colDefB.children) {
                    colDefB.children.sort(sortFn);
                }
                return 0;
            }
            const defA = colDefA;
            const defB = colDefB;
            const indexA = colIdsToIndexes[defA.colId];
            const indexB = colIdsToIndexes[defB.colId];
            return indexA - indexB;
        };
        columnDefs.sort(sortFn);
        return columnDefs;
    }
    /**
     * Compares 2 Layouts for equality
     * @param layout1 First Layout
     * @param layout2 Second Layout
     */
    areLayoutsEqual(layout1, layout2) {
        return areLayoutsEqual(layout1, layout2);
    }
    /**
     * Returns what the layout supports.
     * This takes into account the data-source.
     */
    getLayoutSupportedFeatures() {
        const layoutSupportedFeatures = {
            RowGroupedColumns: true,
            TableAggregationColumns: true,
            PivotAggregationColumns: true,
            PivotColumns: true,
            ColumnFilters: true,
            ColumnSorts: true,
            GridFilter: true,
            RowSummaries: true,
        };
        if (this.getGridApi().isTreeDataGrid()) {
            //  layoutSupportedFeatures.RowGroupedColumns = false;
            layoutSupportedFeatures.PivotColumns = false;
        }
        if (this.getGridApi().getAgGridRowModelType() === 'viewport') {
            layoutSupportedFeatures.RowGroupedColumns = false;
            layoutSupportedFeatures.TableAggregationColumns = false;
            layoutSupportedFeatures.PivotAggregationColumns = false;
            layoutSupportedFeatures.PivotColumns = false;
        }
        if (!this.getFilterOptions().useAdaptableFiltering) {
            layoutSupportedFeatures.ColumnFilters = false;
            layoutSupportedFeatures.GridFilter = false;
        }
        if (this.getEntitlementApi().getEntitlementAccessLevelForModule(ColumnFilterModuleId) == 'Hidden') {
            layoutSupportedFeatures.GridFilter = false;
        }
        if (this.getEntitlementApi().getEntitlementAccessLevelForModule(GridFilterModuleId) == 'Hidden') {
            layoutSupportedFeatures.GridFilter = false;
        }
        if (this._adaptable?.getAgGridRowModelType?.() !== 'clientSide') {
            layoutSupportedFeatures.RowSummaries = false;
        }
        return layoutSupportedFeatures;
    }
    hasLayoutSpecificObjects() {
        const layoutTagOptions = this.getLayoutOptions().layoutTagOptions;
        if (!layoutTagOptions) {
            return false;
        }
        if (layoutTagOptions.autoCheckTagsForLayouts == true ||
            typeof layoutTagOptions?.isObjectExtendedInLayout === 'function') {
            return true;
        }
        return false;
    }
    isObjectExtendedInLayout(object, module, layout) {
        if (!this.hasLayoutSpecificObjects()) {
            return true;
        }
        const layoutTagOptions = this.getLayoutOptions().layoutTagOptions;
        if (layoutTagOptions?.autoCheckTagsForLayouts == true) {
            return ArrayExtensions.IsNullOrEmpty(object.Tags) ? true : object.Tags?.includes(layout.Name);
        }
        const context = {
            adaptableObject: object,
            module,
            layout,
            ...this.getAdaptableInternalApi().buildBaseContext(),
        };
        return layoutTagOptions?.isObjectExtendedInLayout(context);
    }
    showLayoutNonExtendedObjects() {
        return this.getAdaptableState().Internal.Layout.showLayoutNonExtendedObjects;
    }
    isLayoutGrouped(layout) {
        if (!layout) {
            layout = this.getLayoutApi().getCurrentLayout();
        }
        return (layout?.RowGroupedColumns?.length || layout?.PivotGroupedColumns?.length) > 0;
    }
    setupRowSummaries() {
        if (!this._adaptable.agGridModulesAdapter.isAgGridModuleRegistered('PinnedRowModule')) {
            this.getAdaptableApi().consoleError(`Can NOT set Layout Row Summaries - missing required AG Grid module 'PinnedRowModule'`);
            return;
        }
        const rowSummaries = this.getAdaptableState().Internal?.RowSummary?.rowSummaries ?? [];
        const { top, bottom } = rowSummaries.reduce((acc, summaryRow) => {
            const row = summaryRow.RowData;
            if (summaryRow.Position === 'Bottom' || !summaryRow.Position) {
                acc.bottom.push(row);
            }
            else {
                acc.top.push(row);
            }
            return acc;
        }, { top: [], bottom: [] });
        const agGridAdapter = this.getAdaptableInternalApi().getAgGridAdapter();
        agGridAdapter.setGridOption('pinnedTopRowData', top);
        agGridAdapter.setGridOption('pinnedBottomRowData', bottom);
    }
    refreshLayout() {
        this._adaptable.refreshLayout();
    }
    getChangedColumnSorts(oldSorts, newSorts) {
        if (ArrayExtensions.IsNullOrEmpty(oldSorts) && ArrayExtensions.IsNullOrEmpty(newSorts)) {
            return [];
        }
        // If either one is empty but not both, all columns in the non-empty array have changed
        if (ArrayExtensions.IsNullOrEmpty(oldSorts)) {
            return newSorts.map((sort) => sort.ColumnId);
        }
        if (ArrayExtensions.IsNullOrEmpty(newSorts)) {
            return oldSorts.map((sort) => sort.ColumnId);
        }
        const changedColumnIds = [];
        // Create maps for quick lookup
        const oldSortsMap = new Map();
        oldSorts.forEach((sort) => {
            oldSortsMap.set(sort.ColumnId, sort.SortOrder);
        });
        // Check columns in new sorts that changed from old sorts
        newSorts.forEach((newSort) => {
            const oldSortOrder = oldSortsMap.get(newSort.ColumnId);
            // If column wasn't sorted before or sort order changed
            if (oldSortOrder === undefined || oldSortOrder !== newSort.SortOrder) {
                changedColumnIds.push(newSort.ColumnId);
            }
            // Remove processed columns from the map
            oldSortsMap.delete(newSort.ColumnId);
        });
        // Add remaining columns from old sorts (these were removed in new sorts)
        oldSortsMap.forEach((_, columnId) => {
            changedColumnIds.push(columnId);
        });
        return changedColumnIds;
    }
}
