/**
 * Copyright (c) 2020-present, Goldman Sachs
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { action, computed, makeObservable, observable } from 'mobx';
import { deleteEntry, addUniqueEntry, hashArray, } from '@finos/legend-shared';
import { DEFAULT_LAMBDA_VARIABLE_NAME } from '../../../QueryBuilderConfig.js';
import { QueryBuilderDerivationProjectionColumnState, } from '../projection/QueryBuilderProjectionColumnState.js';
import { QUERY_BUILDER_STATE_HASH_STRUCTURE } from '../../../QueryBuilderStateHashUtils.js';
import { QueryBuilderTDSColumnState } from '../QueryBuilderTDSColumnState.js';
export class QueryBuilderAggregateColumnState extends QueryBuilderTDSColumnState {
    aggregationState;
    projectionColumnState;
    lambdaParameterName = DEFAULT_LAMBDA_VARIABLE_NAME;
    operator;
    calendarFunction;
    hideCalendarColumnState = true;
    constructor(aggregationState, projectionColumnState, operator) {
        super();
        makeObservable(this, {
            projectionColumnState: observable,
            lambdaParameterName: observable,
            calendarFunction: observable,
            hideCalendarColumnState: observable,
            operator: observable,
            setHideCalendarColumnState: action,
            setColumnState: action,
            setLambdaParameterName: action,
            setOperator: action,
            setCalendarFunction: action,
            handleUsedPostFilterType: action,
            hashCode: computed,
        });
        this.aggregationState = aggregationState;
        this.projectionColumnState = projectionColumnState;
        this.operator = operator;
    }
    setColumnState(val) {
        this.projectionColumnState = val;
    }
    setLambdaParameterName(val) {
        this.lambdaParameterName = val;
    }
    setHideCalendarColumnState(val) {
        this.hideCalendarColumnState = val;
    }
    setCalendarFunction(val) {
        this.calendarFunction = val;
    }
    setOperator(val) {
        this.operator = val;
    }
    getColumnType() {
        return this.operator.getReturnType(this);
    }
    handleUsedPostFilterType(type) {
        if (this.getColumnType() === undefined &&
            this.projectionColumnState instanceof
                QueryBuilderDerivationProjectionColumnState) {
            this.projectionColumnState.setReturnType(type);
        }
    }
    get hashCode() {
        return hashArray([
            QUERY_BUILDER_STATE_HASH_STRUCTURE.AGGREGATE_COLUMN_STATE,
            this.operator,
            this.calendarFunction ?? '',
        ]);
    }
    get columnName() {
        return this.projectionColumnState.columnName;
    }
}
export class QueryBuilderAggregationState {
    tdsState;
    operators = [];
    calendarFunctions;
    columns = [];
    constructor(tdsState, operators, calendarFunctions) {
        makeObservable(this, {
            columns: observable,
            removeColumn: action,
            addColumn: action,
            changeColumnAggregateOperator: action,
            disableCalendar: action,
            allValidationIssues: computed,
            hashCode: computed,
        });
        this.tdsState = tdsState;
        this.operators = operators;
        this.calendarFunctions = calendarFunctions;
    }
    removeColumn(val) {
        deleteEntry(this.columns, val);
    }
    addColumn(val) {
        addUniqueEntry(this.columns, val);
    }
    changeColumnAggregateOperator(val, projectionColumnState, hideOperatorInColumnName) {
        const aggregateColumnState = this.columns.find((column) => column.projectionColumnState === projectionColumnState);
        const aggreateOperators = this.operators.filter((op) => op.isCompatibleWithColumn(projectionColumnState));
        if (val) {
            if (!aggreateOperators.includes(val)) {
                return;
            }
            if (aggregateColumnState) {
                if (!hideOperatorInColumnName) {
                    const colName = aggregateColumnState.projectionColumnState.columnName.split(`(${aggregateColumnState.operator.getLabel(aggregateColumnState.projectionColumnState)})`)[0] ?? '';
                    aggregateColumnState.projectionColumnState.setColumnName(`${colName} (${val.getLabel(projectionColumnState)})`);
                }
                aggregateColumnState.setOperator(val.getOperator);
            }
            else {
                if (!hideOperatorInColumnName) {
                    projectionColumnState.setColumnName(`${projectionColumnState.columnName} (${val.getLabel(projectionColumnState)})`);
                }
                const newAggregateColumnState = new QueryBuilderAggregateColumnState(this, projectionColumnState, val.getOperator);
                newAggregateColumnState.setOperator(val.getOperator);
                this.addColumn(newAggregateColumnState);
                // automatically move the column to the end
                // as aggregate column should always be the last one
                // NOTE: unless we do `olap` aggregation
                // See https://github.com/finos/legend-studio/issues/253
                this.tdsState.moveColumn(this.tdsState.projectionColumns.indexOf(projectionColumnState), this.tdsState.projectionColumns.length - 1);
            }
        }
        else {
            if (aggregateColumnState) {
                // automatically move the column to the last position before the aggregate columns
                // NOTE: `moveColumn` will take care of this placement calculation
                if (!hideOperatorInColumnName) {
                    const colName = aggregateColumnState.projectionColumnState.columnName.split(`(${aggregateColumnState.operator.getLabel(aggregateColumnState.projectionColumnState)})`)[0] ?? '';
                    aggregateColumnState.projectionColumnState.setColumnName(colName);
                }
                this.tdsState.moveColumn(this.tdsState.projectionColumns.indexOf(projectionColumnState), 0);
                this.removeColumn(aggregateColumnState);
            }
        }
    }
    disableCalendar() {
        this.tdsState.queryBuilderState.setIsCalendarEnabled(false);
        this.columns.forEach((column) => {
            column.setCalendarFunction(undefined);
            column.setHideCalendarColumnState(true);
        });
    }
    get allValidationIssues() {
        return this.columns.map((col) => col.operator.allValidationIssues).flat();
    }
    get hashCode() {
        return hashArray([
            QUERY_BUILDER_STATE_HASH_STRUCTURE.AGGREGATION_STATE,
            hashArray(this.columns),
        ]);
    }
}
//# sourceMappingURL=QueryBuilderAggregationState.js.map