import { ApiBase } from '../Implementation/ApiBase';
import { AG_GRID_GROUPED_COLUMN } from '../../Utilities/Constants/GeneralConstants';
import uniq from 'lodash/uniq';
import StringExtensions from '../../Utilities/Extensions/StringExtensions';
import { isPivotGrandTotal, isPivotResultColumn } from '../Implementation/ColumnApiImpl';
import { destructurePivotColumnId } from '../../layout-manager/src/destructurePivotColumnId';
import { isPivotColumnTotal } from '../../layout-manager/src/isPivotColumnTotal';
import { isPivotAggTotalColumn } from '../../layout-manager/src/isPivotAggTotalColumn';
import { HIDDEN_COLUMN_TYPE } from '../../AdaptableState/Common/AdaptableColumn';
export function getAutoRowGroupColumnIdFor(columnId) {
    return `${AG_GRID_GROUPED_COLUMN}-${columnId}`;
}
export class ColumnInternalApi extends ApiBase {
    /**
     * Retrieves 'ColumnType' property for a given Column
     *   isCumulativeAggregate(input: string): boolean {
     *     return !!this.getNodesFromExpression(input, 'CUMUL')?.length;
     *   }
     * @param columnId Column to use
     */
    getAgGridColumnType(columnId) {
        return this._adaptable.getAgGridColumnType(columnId);
    }
    getAllAgGridColumnTypes() {
        let colTypes = [];
        this.getColumnApi()
            .getColumns()
            .forEach((c) => {
            const agGridColType = this.getAgGridColumnType(c.columnId);
            if (Array.isArray(agGridColType)) {
                colTypes.push(...agGridColType);
            }
            else {
                colTypes.push(agGridColType);
            }
        });
        return uniq(colTypes).filter((c) => StringExtensions.IsNotNullOrEmptyOrWhiteSpace(c));
    }
    /**
     * Retrieves a list providing the Friendly Name / Caption for all columns
     */
    getAllColumnFriendlyNames() {
        return this.getColumnApi()
            .getColumns()
            .map((c) => {
            return c.friendlyName;
        });
    }
    getAutoRowGroupColumnIdFor(columnId) {
        return getAutoRowGroupColumnIdFor(columnId);
    }
    /**
     * Retrieves AG Grid's field property for the column
     * @param columnId columnId to look up
     */
    getAgGridColumnFieldForAdaptableColumn(columnId) {
        const agGridColumn = this.getAgGridColumnForAdaptableColumn(columnId);
        return agGridColumn.getColDef().field || '';
    }
    /**
     * Retrieves AG Grid's column for an Adaptable column
     * @param columnId columnId to look up
     */
    getAgGridColumnForAdaptableColumn(columnId) {
        return this._adaptable.getAgGridColumnForColumnId(columnId);
    }
    getActiveColumnComparator(columnId, customSort, customSortComparer) {
        if ((!customSort || customSort?.IsSuspended) && !customSortComparer) {
            // defaults to AG-Grid column definition comparator if no CustomSort is defined&active
            const colDefComparator = this._adaptable.agGridColumnAdapter.getUserColDefProperty(columnId, 'comparator');
            return colDefComparator;
        }
        // CustomSort Comparer function takes precedence over CustomSort SortedValues
        const comparerFunction = customSortComparer
            ? customSortComparer.comparer
            : this.getCustomSortApi().internalApi.getDefaultCustomSortComparer(customSort.ColumnId, customSort.SortedValues);
        return comparerFunction;
    }
    isSpecialColumn(columnId, column = null) {
        if (column) {
            return column.isCalculatedColumn || column.isFreeTextColumn || column.isActionColumn;
        }
        else
            return (this.getColumnApi().isCalculatedColumn(columnId) ||
                this.getColumnApi().isFreeTextColumn(columnId) ||
                this.getColumnApi().isActionColumn(columnId) ||
                this.getColumnApi().isFdc3Column(columnId));
    }
    getColumnHeaderName(params) {
        // this is the same object, but casting it makes it easier to work with
        const isColumn = !params.columnGroup;
        const columnParams = params;
        const isColumnGroup = !!params.columnGroup;
        const columnGroupParams = params;
        const defaultHeaderName = params.colDef?.headerName ??
            (isColumn ? StringExtensions.CamelCaseToHumanText(columnParams.colDef?.field) : '') ??
            '';
        // for now we override ONLY the header names
        if (params.location !== 'header') {
            return defaultHeaderName;
        }
        // 1. Layout specific header has the highest priority
        const layoutSpecificCustomHeader = this.getLayoutApi().getCurrentLayout().ColumnHeaders?.[isColumn ? columnParams.column.getColId() : columnGroupParams.columnGroup.getGroupId()];
        if (layoutSpecificCustomHeader) {
            return layoutSpecificCustomHeader;
        }
        // 2. check for custom ColumnOptions.columnHeader
        if (typeof this.getColumnOptions().columnHeader === 'function') {
            const columnHeaderContext = this.buildColumnHeaderContext(params, defaultHeaderName);
            if (columnHeaderContext === 'skip') {
                return defaultHeaderName;
            }
            const customHeader = this.getColumnOptions().columnHeader(columnHeaderContext);
            return customHeader;
        }
        // 3. fallback to default header name
        return defaultHeaderName;
    }
    buildColumnHeaderContext(params, defaultHeaderName) {
        const currentLayoutType = this.getLayoutApi().isCurrentLayoutPivot() ? 'pivot' : 'table';
        const currentLayout = this.getLayoutApi().getCurrentLayout();
        const baseContext = {
            ...this.getAdaptableApi().internalApi.buildBaseContext(),
            defaultHeaderName,
            currentLayout,
            currentLayoutName: currentLayout.Name,
            currentLayoutType: currentLayoutType,
        };
        // makes it easier to work with
        const currentTableLayout = currentLayout;
        const currentPivotLayout = currentLayout;
        if (params.column?.getColId() === AG_GRID_GROUPED_COLUMN) {
            const columnType = 'autoGroupColumn';
            return {
                ...baseContext,
                columnType,
                columnId: params.column.getColId(),
                groupedColumnIds: currentLayoutType === 'table'
                    ? currentTableLayout.RowGroupedColumns ?? []
                    : currentPivotLayout.PivotGroupedColumns ?? [],
            };
        }
        if (params.column?.getColId().startsWith(`${AG_GRID_GROUPED_COLUMN}-`)) {
            const columnType = 'rowGroupColumn';
            const columnId = params.column.getColId();
            // remove `${AG_GRID_GROUPED_COLUMN}-` from beginning of columnId
            const groupColumnId = columnId.substring(`${AG_GRID_GROUPED_COLUMN}-`.length);
            return {
                ...baseContext,
                columnType,
                columnId,
                groupColumnId,
            };
        }
        if (baseContext.currentLayoutType === 'table') {
            if (params.columnGroup) {
                const columnType = 'tableColumnGroup';
                if (!params.colDef?.children) {
                    // AG Grid created virtual column groups for all columns
                    // we want to skip those
                    return 'skip';
                }
                return {
                    ...baseContext,
                    columnType,
                    groupId: params.columnGroup?.getGroupId(),
                    childrenColumnIds: params.columnGroup
                        ?.getChildren()
                        .map((col) => {
                        if (col.isColumn) {
                            return col.getColId();
                        }
                    })
                        .filter(Boolean),
                    state: params.columnGroup?.isExpandable() && !params.columnGroup?.isExpanded()
                        ? 'collapsed'
                        : 'expanded',
                };
            }
            if (params.column) {
                const columnType = 'tableColumn';
                return {
                    ...baseContext,
                    columnType,
                    columnId: params.column?.getColId(),
                    aggregation: params.column.getAggFunc(),
                };
            }
        }
        if (baseContext.currentLayoutType === 'pivot') {
            if (params.columnGroup) {
                if (!params.colDef?.pivotKeys) {
                    // we might have user defined colGroups, but we are not interested in them in pivot mode
                    return 'skip';
                }
                const columnType = 'pivotColumnGroup';
                return {
                    ...baseContext,
                    columnType,
                    groupId: params.columnGroup?.getGroupId(),
                    pivotKeys: params.colDef.pivotKeys,
                    state: params.columnGroup?.isExpandable() && !params.columnGroup?.isExpanded()
                        ? 'collapsed'
                        : 'expanded',
                };
            }
            if (params.column) {
                let columnId = params.column.getColId();
                if (isPivotGrandTotal(columnId)) {
                    const columnType = 'pivotGrandTotal';
                    const pivotValueCol = params.colDef.pivotValueColumn;
                    const aggregatedColumnId = pivotValueCol?.getColId();
                    const currentLayoutAggCols = currentPivotLayout.PivotAggregationColumns?.map((col) => col.ColumnId);
                    if (!currentLayoutAggCols?.includes(aggregatedColumnId)) {
                        // this column is not an aggregation column
                        return 'skip';
                    }
                    return {
                        ...baseContext,
                        columnType,
                        aggregatedColumnId,
                        aggregation: pivotValueCol.getAggFunc(),
                    };
                }
                if (isPivotColumnTotal(params.colDef?.colId)) {
                    const columnType = 'pivotColumnTotal';
                    const pivotColInfo = destructurePivotColumnId(params.colDef, {
                        pivotColIds: currentPivotLayout.PivotColumns,
                        aggColIds: currentPivotLayout.PivotAggregationColumns.map((col) => col.ColumnId),
                    }, (message) => this.logWarn(message));
                    if (pivotColInfo === '!unknown!') {
                        return 'skip';
                    }
                    const pivotKey = pivotColInfo.pivotKeys[pivotColInfo.pivotKeys.length - 1];
                    return {
                        ...baseContext,
                        columnType,
                        pivotKey,
                        pivotColumnId: pivotColInfo.pivotColumnId,
                        aggregation: params.colDef?.pivotValueColumn?.getAggFunc(),
                    };
                }
                if (isPivotAggTotalColumn(params.colDef)) {
                    const columnType = 'pivotAggregationTotal';
                    const pivotValueCol = params.colDef.pivotValueColumn;
                    const pivotColInfo = destructurePivotColumnId(params.colDef, {
                        pivotColIds: currentPivotLayout.PivotColumns,
                        aggColIds: currentPivotLayout.PivotAggregationColumns.map((col) => col.ColumnId),
                    }, (message) => this.logWarn(message));
                    if (pivotColInfo === '!unknown!') {
                        return 'skip';
                    }
                    const pivotKey = pivotColInfo.pivotKeys[pivotColInfo.pivotKeys.length - 1];
                    return {
                        ...baseContext,
                        columnType,
                        aggregatedColumnId: pivotValueCol?.getColId(),
                        aggregation: pivotValueCol.getAggFunc(),
                        pivotColumnId: pivotColInfo.pivotColumnId,
                        pivotKey,
                    };
                }
                if (isPivotResultColumn(columnId)) {
                    const columnType = 'pivotResultColumn';
                    const pivotValueCol = params.colDef.pivotValueColumn;
                    const aggregatedColumnId = pivotValueCol?.getColId();
                    const currentLayoutAggCols = currentPivotLayout.PivotAggregationColumns?.map((col) => col.ColumnId);
                    if (!currentLayoutAggCols?.includes(aggregatedColumnId)) {
                        // this column is not an aggregation column
                        return 'skip';
                    }
                    return {
                        ...baseContext,
                        columnType,
                        columnId,
                        pivotKeys: params.colDef.pivotKeys,
                        aggregatedColumnId,
                        aggregation: pivotValueCol.getAggFunc(),
                    };
                }
            }
        }
        // if nothing matched, we skip this column[group]
        return 'skip';
    }
    hasArrayDataType(column) {
        return ['textArray', 'numberArray', 'tupleArray', 'objectArray'].includes(column.dataType);
    }
    getQueryableColumnsForUIEditor() {
        return this.getColumnApi()
            .getQueryableColumns()
            .filter((column) => !column.isGeneratedPivotResultColumn && !column.isGeneratedRowGroupColumn);
    }
    isAlwaysHiddenColumn(columnIdentifier) {
        return this.getColumnApi().hasColumnType(columnIdentifier, HIDDEN_COLUMN_TYPE);
    }
    getColumnDateTypes() {
        // this is required because Adaptable uses 'date' type for all AG Grid date types: 'date', 'dateString'
        return ['date', 'dateString'];
    }
}
