import { ApiBase } from './ApiBase';
import * as GeneralConstants from '../../Utilities/Constants/GeneralConstants';
import { AG_GRID_SELECTION_COLUMN } from '../../Utilities/Constants/GeneralConstants';
import * as ModuleConstants from '../../Utilities/Constants/ModuleConstants';
import { ColumnInternalApi } from '../Internal/ColumnInternalApi';
import { AUTO_GROUP_COLUMN_ID__MULTI_PREFIX, AUTO_GROUP_COLUMN_ID__SINGLE, } from '../../layout-manager/src/normalizeLayoutModel';
import ArrayExtensions from '../../Utilities/Extensions/ArrayExtensions';
import { isPivotColumnTotal } from '../../layout-manager/src/isPivotColumnTotal';
import { isPivotLayout } from './LayoutHelpers';
const ROW_GROUP_COLUMN_DEFAULTS = {
    columnId: '',
    isTreeColumn: false,
    friendlyName: 'Group',
    isPrimaryKey: false,
    readOnly: false,
    resizable: true,
    visible: true,
    alwaysHidden: false,
    fieldOnly: false,
    queryable: false,
    sortable: false,
    filterable: false,
    groupable: false,
    pivotable: false,
    aggregatable: false,
    moveable: true,
    hideable: false,
    exportable: true,
    isGrouped: true,
    isGeneratedRowGroupColumn: true,
    isGeneratedPivotResultColumn: false,
    isGeneratedSelectionColumn: false,
    isFixed: false,
    pinned: null,
    isSparkline: false,
    dataType: 'text',
    isCalculatedColumn: false,
    isFreeTextColumn: false,
    isActionColumn: false,
    isPivotTotalColumn: false,
};
export function generateAutoRowGroupSingleColumn() {
    return {
        ...ROW_GROUP_COLUMN_DEFAULTS,
        columnId: AUTO_GROUP_COLUMN_ID__SINGLE,
    };
}
const TREE_COLUMN_FRIENDLY_NAME = '[Tree Column]';
export function generateAutoTreeSingleColumn() {
    return {
        ...ROW_GROUP_COLUMN_DEFAULTS,
        columnId: AUTO_GROUP_COLUMN_ID__SINGLE,
        isTreeColumn: true,
        friendlyName: TREE_COLUMN_FRIENDLY_NAME,
    };
}
export function generateAutoRowGroupColumnForColumn(column) {
    return {
        ...ROW_GROUP_COLUMN_DEFAULTS,
        columnId: AUTO_GROUP_COLUMN_ID__MULTI_PREFIX + column.columnId,
        friendlyName: column.friendlyName,
        dataType: column.dataType,
    };
}
export function getFriendlyNameForPivotResultColumn(columnId, agGridApi) {
    if (isPivotGrandTotal(columnId)) {
        return `[Grand Total] ${columnId
            .split('_')
            .slice(2)
            .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
            .join(' ')}`;
    }
    if (isPivotColumnTotal(columnId)) {
        return `[Group Total] ${columnId
            .split('_')
            .slice(2)
            .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
            .join(' ')}`;
    }
    // is quite consuming on performance
    // we don't need it anyway because currently (20.0.7) we don't display Pivot Totals at all
    // if (isPivotAggregationTotalColumn(columnId, agGridApi)) {
    //   return `[Aggregation Total] ${columnId
    //     .split('_')
    //     .slice(2)
    //     .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
    //     .join(' ')}`;
    // }
    return `[Pivot] ${columnId
        .split('_')
        .slice(1)
        .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
        .join(' ')}`;
}
export function isPivotResultColumn(columnId) {
    // put this here as there might be other indicators we are not aware of?
    return columnId?.startsWith(GeneralConstants.AG_GRID_PIVOT_COLUMN);
}
export function isPivotGrandTotal(columnId) {
    return columnId?.startsWith(GeneralConstants.AG_GRID_PIVOT_GRAND_TOTAL_COLUMN);
}
export class ColumnApiImpl extends ApiBase {
    constructor(_adaptable) {
        super(_adaptable);
        this.internalApi = new ColumnInternalApi(_adaptable);
    }
    getColumns() {
        return this.getGridApi().getInternalState().Columns ?? [];
    }
    getUIAvailableColumns() {
        return this.getColumns().filter((c) => !c.alwaysHidden &&
            !c.isGeneratedSelectionColumn &&
            // currently (20.0.7) we don't display Pivot Totals in UI
            !c.isPivotTotalColumn);
    }
    getSpecialColumns() {
        const cols = this.getUIAvailableColumns()?.filter((c) => this.internalApi.isSpecialColumn(c.columnId, c));
        return cols ?? [];
    }
    getNonSpecialColumns() {
        const cols = this.getUIAvailableColumns()?.filter((c) => !this.internalApi.isSpecialColumn(c.columnId, c));
        return cols ?? [];
    }
    getVisibleColumns() {
        const layout = this.getLayoutApi().getCurrentLayout();
        const allcols = this.getUIAvailableColumns();
        if (isPivotLayout(layout)) {
            return allcols;
        }
        const visibleCols = layout.TableColumns.reduce((acc, colId) => {
            if (layout.ColumnVisibility?.[colId] !== false) {
                acc.add(colId);
            }
            return acc;
        }, new Set());
        return allcols.filter((c) => visibleCols.has(c.columnId));
    }
    selectColumn(columnId) {
        this._adaptable.selectColumn(columnId);
    }
    selectColumns(columnIds) {
        this._adaptable.selectColumns(columnIds);
    }
    addColumnToSelection(columnId) {
        this._adaptable.selectColumn(columnId, { keepExistingSelection: true });
    }
    addColumnsToSelection(columnIds) {
        this._adaptable.selectColumns(columnIds, { keepExistingSelection: true });
    }
    selectAllColumns() {
        this._adaptable.selectAll();
    }
    autosizeColumn(columnId) {
        this._adaptable.autoSizeColumn(columnId);
    }
    autosizeColumns(columnIds) {
        this._adaptable.autoSizeColumns(columnIds);
    }
    autosizeAllColumns() {
        this._adaptable.autoSizeAllColumns();
    }
    hideColumn(columnId) {
        this._adaptable.hideColumn(columnId);
    }
    showColumn(columnId) {
        this._adaptable.showColumn(columnId);
    }
    isPivotResultColumn(columnId) {
        return isPivotResultColumn(columnId) || isPivotGrandTotal(columnId);
    }
    isSelectionColumn(columnId) {
        return columnId === AG_GRID_SELECTION_COLUMN;
    }
    isAutoRowGroupColumn(columnId) {
        return (this.isAutoRowGroupColumnForSingle(columnId) || this.isAutoRowGroupColumnForMulti(columnId));
    }
    isAutoRowGroupColumnForSingle(columnId) {
        return columnId === AUTO_GROUP_COLUMN_ID__SINGLE;
    }
    isAutoRowGroupColumnForMulti(columnId) {
        return columnId.startsWith(AUTO_GROUP_COLUMN_ID__MULTI_PREFIX);
    }
    isSpecialColumn(columnId) {
        return (this.isCalculatedColumn(columnId) ||
            this.isFreeTextColumn(columnId) ||
            this.isActionColumn(columnId) ||
            this.isFdc3Column(columnId));
    }
    isCalculatedColumn(columnId) {
        return (this.getCalculatedColumnApi()
            .getCalculatedColumns()
            .find((cc) => cc.ColumnId == columnId) != null);
    }
    isFreeTextColumn(columnId) {
        return (this.getFreeTextColumnApi()
            .getFreeTextColumns()
            .find((cc) => cc.ColumnId == columnId) != null);
    }
    isActionColumn(columnId) {
        return (this.getActionColumnApi()
            .getActionColumns()
            ?.find((cc) => cc.columnId == columnId) != null);
    }
    isFdc3Column(columnId) {
        return this.getFdc3Api().internalApi.getFdc3ColumnIds().includes(columnId);
    }
    getColumnWithColumnId(columnId, logWarning) {
        if (columnId == undefined) {
            return;
        }
        // just return null if no columns rather than logging a warning - otherwise get lots at startup
        if (ArrayExtensions.IsNullOrEmpty(this.getColumns())) {
            return;
        }
        const foundColumn = this.getColumns().find((c) => c.columnId == columnId);
        if (foundColumn) {
            return foundColumn;
        }
        if (logWarning) {
            this.logMissingColumnWarning(columnId);
        }
        return undefined;
    }
    hasNumberDataType(columnId) {
        const column = this.getColumnWithColumnId(columnId);
        if (!column) {
            return false;
        }
        return column?.dataType == 'number';
    }
    hasBooleanDataType(columnId) {
        const column = this.getColumnWithColumnId(columnId);
        if (!column) {
            return false;
        }
        return column?.dataType == 'boolean';
    }
    hasArrayDataType(columnId) {
        return this.hasTextArrayDataType(columnId) || this.hasNumericArrayDataType(columnId);
    }
    hasTextArrayDataType(columnId) {
        const column = this.getColumnWithColumnId(columnId);
        if (!column) {
            return false;
        }
        return column?.dataType === 'textArray';
    }
    hasNumericArrayDataType(columnId) {
        const column = this.getColumnWithColumnId(columnId);
        if (!column) {
            return false;
        }
        return (column?.dataType === 'numberArray' ||
            column?.dataType === 'tupleArray' ||
            column?.dataType === 'objectArray');
    }
    hasDateDataType(columnId) {
        const column = this.getColumnWithColumnId(columnId);
        if (!column) {
            return false;
        }
        return this.internalApi.getColumnDateTypes().includes(column?.dataType);
    }
    getColumnDataTypeForColumnId(columnId) {
        const column = this.getColumnWithColumnId(columnId);
        if (!column) {
            return undefined;
        }
        return column.dataType;
    }
    getFriendlyNameForColumnId(columnId, layout) {
        if (this.isPivotResultColumn(columnId)) {
            return getFriendlyNameForPivotResultColumn(columnId, this.getAgGridApi());
        }
        const foundColumn = this.getColumns().find((c) => c.columnId === columnId);
        const isRowGroupColumn = this.isAutoRowGroupColumn(columnId);
        if (foundColumn &&
            foundColumn.friendlyName &&
            !foundColumn.friendlyName.includes(GeneralConstants.MISSING_COLUMN) &&
            !isRowGroupColumn) {
            return foundColumn.friendlyName;
        }
        if (foundColumn?.isTreeColumn && isRowGroupColumn) {
            return foundColumn.friendlyName;
        }
        let result = columnId + GeneralConstants.MISSING_COLUMN;
        if (this.isAutoRowGroupColumn(columnId)) {
            if (this.getGridApi().isTreeDataGrid()) {
                return TREE_COLUMN_FRIENDLY_NAME;
            }
            const currentLayout = layout ?? this.getLayoutApi().getCurrentLayout();
            const groupColumns = currentLayout?.RowGroupedColumns ?? currentLayout?.PivotGroupedColumns ?? [];
            if (groupColumns.length) {
                const groupedByLabel = this.isAutoRowGroupColumnForSingle(columnId)
                    ? groupColumns.map((colId) => this.getFriendlyNameForColumnId(colId, layout)).join(', ')
                    : this.getFriendlyNameForColumnId(columnId.replace(AUTO_GROUP_COLUMN_ID__MULTI_PREFIX, ''), layout);
                result = `[Grouped Column: ${groupedByLabel}]`;
                return result;
            }
        }
        this.logMissingColumnWarning(columnId);
        return result;
    }
    doesColumnExist(columnId) {
        const foundColumn = this.getColumns().find((c) => c.columnId === columnId);
        return foundColumn ? true : false;
    }
    getFriendlyNamesForColumnIds(columnIds) {
        const friendlyNames = [];
        if (ArrayExtensions.IsNullOrEmpty(columnIds)) {
            return friendlyNames;
        }
        columnIds.forEach((c) => {
            friendlyNames.push(this.getFriendlyNameForColumnId(c));
        });
        return friendlyNames;
    }
    getColumnIdForFriendlyName(friendlyName) {
        if (friendlyName.includes(GeneralConstants.MISSING_COLUMN)) {
            return friendlyName.replace(GeneralConstants.MISSING_COLUMN, ''); // Ids should stay "pure"
        }
        const foundColumn = this.getColumns().find((c) => c.friendlyName === friendlyName);
        if (foundColumn) {
            return foundColumn.columnId;
        }
        this.logMissingColumnWarning(friendlyName);
        return friendlyName + GeneralConstants.MISSING_COLUMN;
    }
    getColumnIdsForFriendlyNames(friendlyNames) {
        const columnIds = [];
        if (ArrayExtensions.IsNullOrEmpty(friendlyNames)) {
            return columnIds;
        }
        friendlyNames.forEach((c) => {
            columnIds.push(this.getColumnIdForFriendlyName(c));
        });
        return columnIds;
    }
    getColumnsWithFriendlyNames(friendlyNames) {
        return friendlyNames
            .map((friendlyName) => this.getColumns().find((x) => x.friendlyName === friendlyName))
            .filter(Boolean);
    }
    getColumnsWithColumnIds(columnIds, logWarning = true) {
        let returnCols = [];
        columnIds.forEach((c) => {
            const column = this.getColumnWithColumnId(c, logWarning);
            if (column) {
                returnCols.push(column);
            }
        });
        return returnCols;
    }
    isColumnInGrid(columnId) {
        return !!this.getColumnWithColumnId(columnId, false);
    }
    getColumnWithFriendlyName(columnFriendlyName, logWarning = true) {
        // just return null if no columns rather than logging a warning - otherwise get lots at startup
        if (ArrayExtensions.IsNullOrEmpty(this.getColumns())) {
            return null;
        }
        const foundColumn = this.getColumns().find((c) => c.friendlyName === columnFriendlyName);
        if (foundColumn) {
            return foundColumn;
        }
        if (logWarning) {
            this.logMissingColumnWarning(columnFriendlyName);
        }
        return null;
    }
    getColumnsWithDataType(dataType) {
        switch (dataType) {
            case 'boolean':
                return this.getBooleanColumns();
            case 'date':
                return this.getDateColumns();
            case 'number':
                return this.getNumericColumns();
            case 'text':
                return this.getTextColumns();
            case 'textArray':
                return this.getTextArrayColumns();
            case 'numberArray':
                return this.getNumberArrayColumns();
            case 'objectArray':
                return this.getObjectNumberArrayColumns();
            case 'tupleArray':
                return this.getTupleNumberArrayColumns();
            default:
                return this.getUIAvailableColumns();
        }
    }
    getNumericColumns() {
        return this.getUIAvailableColumns().filter((c) => c.dataType === 'number');
    }
    getNumericArrayColumns() {
        return this.getNumberArrayColumns()
            .concat(this.getTupleNumberArrayColumns())
            .concat(this.getObjectNumberArrayColumns());
    }
    getNumberArrayColumns() {
        return this.getUIAvailableColumns().filter((c) => c.dataType === 'numberArray');
    }
    getTupleNumberArrayColumns() {
        return this.getUIAvailableColumns().filter((c) => c.dataType === 'tupleArray');
    }
    getObjectNumberArrayColumns() {
        return this.getUIAvailableColumns().filter((c) => c.dataType === 'objectArray');
    }
    getTextColumns() {
        return this.getUIAvailableColumns().filter((c) => c.dataType === 'text');
    }
    getTextArrayColumns() {
        return this.getUIAvailableColumns().filter((c) => c.dataType === 'textArray');
    }
    getDateColumns() {
        return this.getUIAvailableColumns().filter((c) => c.dataType === 'date');
    }
    getBooleanColumns() {
        return this.getUIAvailableColumns().filter((c) => c.dataType === 'boolean');
    }
    getArrayColumns() {
        return this.getUIAvailableColumns().filter((c) => c.dataType === 'numberArray' ||
            c.dataType === 'tupleArray' ||
            c.dataType === 'objectArray' ||
            c.dataType === 'textArray');
    }
    getSortableColumns() {
        return this.getUIAvailableColumns().filter((c) => c.sortable);
    }
    getFilterableColumns() {
        return this.getUIAvailableColumns().filter((c) => c.filterable);
    }
    getGroupableColumns() {
        return this.getUIAvailableColumns().filter((c) => c.groupable);
    }
    getPivotableColumns() {
        return this.getUIAvailableColumns().filter((c) => c.pivotable);
    }
    getAggregatableColumns() {
        return this.getUIAvailableColumns().filter((c) => c.aggregatable && c.dataType === 'number');
    }
    getQueryableColumns() {
        return this.getColumns().filter((c) => c.queryable);
    }
    getExportableColumns() {
        return this.getColumns().filter((c) => c.exportable);
    }
    getAlwaysHiddenColumns() {
        return this.getColumns().filter((c) => c.alwaysHidden);
    }
    logMissingColumnWarning(columnId) {
        if (this.getColumnOptions().showMissingColumnsWarning === true) {
            if (!this.isAutoRowGroupColumn(columnId) && !this.isSpecialColumn(columnId)) {
                this.logWarn(`No column found named '${columnId}'`);
            }
        }
    }
    getPrimaryKeyColumn() {
        return this.getColumnWithColumnId(this.getOptions().primaryKey);
    }
    getDefaultAggFunc(columnId) {
        const abColumn = this.getColumnWithColumnId(columnId);
        const availableAggregationFunctions = abColumn.availableAggregationFunctions;
        const agColumn = this.internalApi.getAgGridColumnForAdaptableColumn(columnId)?.getColDef?.();
        return agColumn?.defaultAggFunc ?? availableAggregationFunctions[0];
    }
    openColumnInfoSettingsPanel() {
        this.showModulePopup(ModuleConstants.ColumnInfoModuleId);
    }
    getColumnTypes() {
        const columnTypes = this.getOptions().columnOptions.columnTypes;
        if (typeof columnTypes === 'function') {
            const types = this.internalApi.getAllAgGridColumnTypes();
            const columnTypesContext = {
                types,
                ...this.getAdaptableInternalApi().buildBaseContext(),
            };
            return columnTypes(columnTypesContext);
        }
        else {
            return columnTypes;
        }
    }
    getColumnsByColumnType(columnType) {
        const abColumns = this.getColumns();
        return abColumns.filter((c) => {
            return (c.columnTypes ?? []).includes(columnType);
        });
    }
    getRowGroupedColumns() {
        return this.getLayoutApi()
            .getCurrentRowGroupsColumnIds()
            ?.map((n) => {
            return this.getColumnWithColumnId(n);
        });
    }
    setColumnCaption(columnId, caption) {
        return this.getLayoutApi().setColumnCaption(columnId, caption);
    }
    getAGGridColDefForColumnId(columnId) {
        return this.getAgGridApi().getColumnDef(columnId);
    }
    getAGGridColumnForColumnId(columnId) {
        return this.getAgGridApi().getColumn(columnId);
    }
    hasColumnType(columnIdentifier, columnType) {
        if (!columnIdentifier) {
            return false;
        }
        const colDef = typeof columnIdentifier === 'string'
            ? this.getAgGridApi().getColumnDef(columnIdentifier)
            : columnIdentifier;
        if (!colDef?.type) {
            return false;
        }
        if (Array.isArray(colDef.type)) {
            return colDef.type.includes(columnType);
        }
        else {
            return colDef.type === columnType;
        }
    }
    getColumnSummaryForColumnId(columnId) {
        const column = this.getColumnWithColumnId(columnId);
        if (!column) {
            return undefined;
        }
        const gridCellsWithCount = this._adaptable.getDistinctGridCellsForColumn(column);
        const columnFilter = this.getColumnFilterApi().getColumnFilterForColumn(column.columnId);
        const uniqueGridCells = gridCellsWithCount.map((gcWithCount) => {
            return {
                rawValue: gcWithCount.rawValue,
                normalisedValue: gcWithCount.normalisedValue,
                displayValue: gcWithCount.displayValue,
                visible: gcWithCount.visible,
                count: gcWithCount.count,
                visibleCount: gcWithCount.visibleCount,
            };
        });
        return {
            column,
            columnFilter,
            uniqueGridCells,
        };
    }
    isAgGridGeneratedColumn(columnId) {
        const column = this.getColumnWithColumnId(columnId);
        if (!column) {
            return true;
        }
        return (column.isGeneratedRowGroupColumn ||
            column.isGeneratedSelectionColumn ||
            column.isGeneratedPivotResultColumn);
    }
}
