"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RowSummaryService = void 0;
const tslib_1 = require("tslib");
const RowSummary_1 = require("../../AdaptableState/Common/RowSummary");
const InternalRedux_1 = require("../../Redux/ActionsReducers/InternalRedux");
const ModuleConstants = tslib_1.__importStar(require("../../Utilities/Constants/ModuleConstants"));
const Helper_1 = tslib_1.__importDefault(require("../Helpers/Helper"));
const AggregatedScalarLiveValue_1 = require("./AggregatedScalarLiveValue");
const ObjectExtensions_1 = require("../Extensions/ObjectExtensions");
const throttle_1 = tslib_1.__importDefault(require("../utils/throttle"));
const isEqual_1 = tslib_1.__importDefault(require("../utils/isEqual"));
/**
 * The logic is extracted here to make it easier to follow
 */
class RowSummaryService {
    api;
    cachedCellSummary = new Map();
    previousRowSummaries;
    previousLayout;
    constructor(api) {
        this.api = api;
    }
    onAdaptableReady() {
        this.rowSummariesSubscriptions();
    }
    rowSummariesSubscriptions() {
        // return;
        if (this.api.isDestroyed()) {
            return;
        }
        // Currently not available for serverside model
        if (!this.api.layoutApi.internalApi.getLayoutSupportedFeatures().RowSummaries) {
            return;
        }
        this.throttledEvaluateRowSummary();
        this.api.eventApi.on('AdaptableStateReloaded', () => {
            this.throttledEvaluateRowSummary();
        });
        this.api.internalApi
            .getDataService()
            .on('RowDataChanged', (rowDataChangedInfo) => {
            this.throttledEvaluateRowSummary();
        });
        this.api.eventApi.on('CellChanged', (event) => {
            const columnId = event.cellDataChange.column.columnId;
            this.throttledEvaluateRowSummary({
                columnIds: [columnId],
            });
        });
        this.api.eventApi.on('LayoutChanged', (event) => {
            // exclude filter events, those are handled in another event
            if (event.actionName.includes('FILTER')) {
                return;
            }
            setTimeout(() => {
                // the timeout is added so the grid has time to repond to the layout changed
                this.throttledEvaluateRowSummary();
            }, 16);
        });
        const adaptable = this.api.internalApi.getAdaptableInstance();
        adaptable._on('AdapTableFiltersApplied', () => {
            // we need to use this instead of layout changed so the rows have time to update
            this.throttledEvaluateRowSummary();
        });
        adaptable._on('FirstDataRendered', () => {
            this.throttledEvaluateRowSummary();
        });
    }
    _throttleAcumulatedColumnsThatChanged = new Set();
    throttledEvaluateRowSummary(reason) {
        if (reason) {
            reason.columnIds.forEach((col) => this._throttleAcumulatedColumnsThatChanged.add(col));
        }
        this._throttledEvaluateRowSummary(reason);
    }
    /**
     *
     * @param colId optional to evaluate only one column
     */
    _throttledEvaluateRowSummary = (0, throttle_1.default)(this.evaluateRowSummary, 300);
    evaluateRowSummary(reason) {
        if (this._throttleAcumulatedColumnsThatChanged.size > 0) {
            const columnIds = Array.from(this._throttleAcumulatedColumnsThatChanged.values());
            reason = {
                columnIds,
            };
            this._throttleAcumulatedColumnsThatChanged.clear();
        }
        if (this.api.isDestroyed() || this.api.layoutApi.isCurrentLayoutPivot()) {
            return;
        }
        const currentLayout = this.api.layoutApi.getCurrentLayout();
        let previousLayout = this.previousLayout;
        // it is added here to be sure it is saved
        this.previousLayout = currentLayout;
        /**
         * If the previous & current layout does not have row summaries, it is safe to exit
         */
        if ((0, ObjectExtensions_1.isObjectEmpty)(currentLayout?.RowSummaries) && (0, ObjectExtensions_1.isObjectEmpty)(previousLayout?.RowSummaries)) {
            return;
        }
        const rowSummaries = currentLayout.RowSummaries ?? [];
        const aggColsMap = (currentLayout.TableAggregationColumns || []).reduce((acc, { ColumnId, AggFunc }) => {
            acc[ColumnId] = AggFunc;
            return acc;
        }, {});
        const rowSummariesResults = rowSummaries
            .filter((rowSummary) => !rowSummary.IsSuspended)
            .map((rowSummary, index) => {
            const { ColumnsMap, Position, 
            // it defaults to true
            IncludeOnlyFilteredRows = true, } = rowSummary;
            return {
                Position,
                RowData: Object.entries(ColumnsMap ?? {}).reduce((acc, [columnId, expression]) => {
                    if (columnId === 'Uuid' || columnId === 'Source' || columnId === 'AdaptableVersion') {
                        return acc;
                    }
                    const key = `${columnId}-${expression}-IncludeOnlyFilteredRows=${IncludeOnlyFilteredRows ? 'filtered' : 'all'}`;
                    let expressionLiveValue = this.cachedCellSummary.get(key);
                    if (expressionLiveValue) {
                        if (!reason) {
                            // refresh all of them
                            expressionLiveValue.refresh();
                        }
                        else if ('columnIds' in reason && reason.columnIds.includes(columnId)) {
                            expressionLiveValue.refresh();
                        }
                    }
                    if (!expressionLiveValue) {
                        try {
                            let aggregatedScalarExpression = `${expression}([${columnId}])`;
                            if (aggregatedScalarExpression.includes(RowSummary_1.WEIGHTED_AVERAGE_AGGREGATED_FUNCTION) &&
                                aggColsMap[columnId] &&
                                typeof aggColsMap[columnId] === 'object') {
                                const weight = aggColsMap[columnId].weightedColumnId;
                                if (weight) {
                                    aggregatedScalarExpression = `AVG([${columnId}], WEIGHT([${weight}]))`;
                                }
                            }
                            expressionLiveValue = new AggregatedScalarLiveValue_1.AggregatedScalarLiveValue({
                                aggregatedScalarExpression,
                            }, ModuleConstants.LayoutModuleId, this.api, () => {
                                if (rowSummary.IncludeOnlyFilteredRows ?? true) {
                                    return this.api.gridApi.getVisibleRowNodes();
                                }
                                else {
                                    return this.api.gridApi.getAllRowNodes();
                                }
                            });
                        }
                        catch (e) {
                            this.api.logError('Error evaluating row summary', e);
                        }
                        this.cachedCellSummary.set(key, expressionLiveValue);
                    }
                    let value = null;
                    if (expressionLiveValue) {
                        value = expressionLiveValue.getGlobalAggregatedValue();
                        if (typeof value === 'number' && !isNaN(value)) {
                            value = Helper_1.default.roundNumber(value, 2);
                        }
                    }
                    const column = this.api.columnApi.getColumnWithColumnId(columnId);
                    const fieldName = column?.field ?? column?.columnId ?? columnId;
                    acc = this.api.internalApi.setValueUsingField(acc, fieldName, value);
                    return acc;
                }, {
                    [RowSummary_1.ROW_SUMMARY_ROW_ID]: `row-summary-${index}`,
                }),
            };
        });
        if (this.previousRowSummaries && (0, isEqual_1.default)(rowSummariesResults, this.previousRowSummaries)) {
            return;
        }
        this.api.internalApi.dispatchReduxAction((0, InternalRedux_1.RowSummarySet)(rowSummariesResults));
        this.previousRowSummaries = rowSummariesResults;
    }
}
exports.RowSummaryService = RowSummaryService;
