import * as PlusMinusRedux from '../Redux/ActionsReducers/PlusMinusRedux';
import * as ModuleConstants from '../Utilities/Constants/ModuleConstants';
import { ArrayExtensions } from '../Utilities/Extensions/ArrayExtensions';
import { Helper } from '../Utilities/Helpers/Helper';
import { AdaptableModuleBase } from './AdaptableModuleBase';
import { PlusMinusModuleId } from '../Utilities/Constants/ModuleConstants';
import { getObjectTagsViewItems } from '../Utilities/getObjectTagsViewItems';
import { getRuleViewItems } from '../Utilities/getRuleViewItems';
import { getScopeViewItems } from '../Utilities/getScopeViewItems';
import { MovePlusMinus } from '../View/PlusMinus/MovePlusMinus';
import { PlusMinusWizard } from '../View/PlusMinus/Wizard/PlusMinusWizard';
import { errorOnce } from '../agGrid/AdaptableLogger';
export class PlusMinusModule extends AdaptableModuleBase {
    shouldHandleKeyDown;
    adaptable;
    constructor(api) {
        super(ModuleConstants.PlusMinusModuleId, ModuleConstants.PlusMinusFriendlyName, 'add-circle', 'PlusMinusPopup', 'Configure how a cell value will edit when the + or - keys are pressed', api);
        this.shouldHandleKeyDown = false;
        this.adaptable = api.internalApi.getAdaptableInstance();
    }
    getModuleAdaptableObjects(config) {
        return this.api.plusMinusApi.getAllPlusMinus(config);
    }
    getExplicitlyReferencedColumnIds(plusMinusNudge) {
        if (this.api.columnScopeApi.scopeHasColumns(plusMinusNudge.Scope)) {
            return this.api.columnScopeApi
                .getColumnsInScope(plusMinusNudge.Scope)
                .map((adaptableColumn) => adaptableColumn.columnId);
        }
        return [];
    }
    getReferencedNamedQueryNames(plusMinusNudge) {
        if (!plusMinusNudge.Rule?.BooleanExpression) {
            return [];
        }
        return this.api.namedQueryApi.internalApi.getReferencedNamedQueryNames(plusMinusNudge.Rule?.BooleanExpression);
    }
    onAdaptableReady() {
        let plusMinusNudges = this.api.plusMinusApi.getAllPlusMinus();
        this.shouldHandleKeyDown = ArrayExtensions.IsNotNullOrEmpty(plusMinusNudges);
        if (this.shouldHandleKeyDown) {
            this.setupKeyDownListener();
        }
    }
    setupKeyDownListener() {
        this.adaptable._on('KeyDown', (keyDownEvent) => {
            this.handleKeyDown(keyDownEvent);
        });
    }
    checkListenToKeyDown() {
        const oldShouldHandleKeyDown = this.shouldHandleKeyDown;
        const newShouldHandleKeyDown = ArrayExtensions.IsNotNullOrEmpty(this.api.plusMinusApi.getAllPlusMinus());
        if (!oldShouldHandleKeyDown && newShouldHandleKeyDown) {
            this.setupKeyDownListener();
        }
        this.shouldHandleKeyDown = newShouldHandleKeyDown;
    }
    createColumnMenuItems(column) {
        if (column && this.isModuleEditable() && column.dataType == 'number') {
            let popupParam = {
                column: column,
                action: 'New',
                source: 'ColumnMenu',
            };
            return [
                this.createMenuItemShowPopup('plus-minus-add', 'Create Plus/Minus Rule', this.moduleInfo.Popup, this.moduleInfo.Glyph, popupParam),
            ];
        }
    }
    handleKeyDown(keyEvent) {
        if (this.shouldHandleKeyDown) {
            //it's a special key so we handle the string representation of the key '
            let keyEventString = Helper.getStringRepresentionFromKey(keyEvent);
            if (keyEventString == '-' || keyEventString == '+') {
                let plusMinusNudges = this.api.plusMinusApi.getAllActivePlusMinus();
                if (ArrayExtensions.IsNotNullOrEmpty(plusMinusNudges)) {
                    let side = keyEventString == '-' ? 'down' : 'up';
                    let selectedCellInfo = this.api.gridApi.getSelectedCellInfo();
                    let isPlusMinusApplicable = this.applyPlusMinus(plusMinusNudges, selectedCellInfo.gridCells, side);
                    if (isPlusMinusApplicable) {
                        keyEvent.preventDefault();
                    }
                }
            }
        }
    }
    applyPlusMinus(plusMinusNudges, cellsToUpdate, direction) {
        let shouldApplyPlusMinus = false;
        let successfulValues = [];
        let failedPreventEdits = [];
        let side = direction == 'up' ? 1 : -1;
        cellsToUpdate.forEach((gridCell) => {
            if (gridCell.column &&
                gridCell.column.dataType == 'number' &&
                this.api.gridApi.isCellEditable(gridCell)) {
                let foundRule;
                let replacementGridCell;
                plusMinusNudges.forEach((pmr) => {
                    if (!foundRule) {
                        if (this.api.columnScopeApi.isColumnInScope(gridCell.column, pmr.Scope)) {
                            //for aggrid as we are getting strings sometimes
                            if (typeof gridCell.rawValue != 'number') {
                                gridCell.rawValue = parseFloat(gridCell.rawValue);
                            }
                            const isSatisfiedExpression = this.isPlusMinusNudgeApplied(pmr, gridCell);
                            if (isSatisfiedExpression) {
                                foundRule = pmr;
                                shouldApplyPlusMinus = true;
                                let computedValue = gridCell.rawValue + pmr.NudgeValue * side;
                                //avoid the 0.0000000000x??
                                //   computedValue=   parseFloat(computedValue.toFixed(12));
                                replacementGridCell = {
                                    primaryKeyValue: gridCell.primaryKeyValue,
                                    column: gridCell.column,
                                    rawValue: computedValue,
                                    displayValue: computedValue,
                                    normalisedValue: computedValue,
                                    rowNode: gridCell.rowNode,
                                    isPivotCell: false,
                                    isRowGroupCell: false,
                                };
                            }
                        }
                    }
                });
                if (foundRule && replacementGridCell) {
                    const dataChangedEvent = this.api.internalApi.buildCellDataChangedInfo({
                        oldValue: Number(gridCell.rawValue),
                        newValue: replacementGridCell.rawValue,
                        column: gridCell.column,
                        primaryKeyValue: gridCell.primaryKeyValue,
                        rowNode: gridCell.rowNode,
                        trigger: 'edit',
                    });
                    let validationRules = this.api.internalApi
                        .getValidationService()
                        .getValidationRulesForDataChange(dataChangedEvent);
                    if (validationRules.length > 0) {
                        failedPreventEdits.push(validationRules[0]);
                    }
                    else {
                        successfulValues.push(replacementGridCell);
                    }
                }
            }
        });
        this.ShowErrorPreventMessage(failedPreventEdits);
        if (ArrayExtensions.IsNotNullOrEmpty(successfulValues)) {
            const cellUpdateRequests = [];
            successfulValues.forEach((gridCell) => {
                cellUpdateRequests.push({
                    columnId: gridCell.column.columnId,
                    newValue: gridCell.normalisedValue,
                    primaryKeyValue: gridCell.primaryKeyValue,
                    rowNode: gridCell.rowNode,
                });
            });
            this.api.plusMinusApi.applyPlusMinus(cellUpdateRequests);
        }
        return shouldApplyPlusMinus;
    }
    isPlusMinusNudgeApplied(plusMinusNudge, gridCell) {
        if (plusMinusNudge.Rule?.BooleanExpression) {
            return this.evaluateExpression(plusMinusNudge, gridCell.rowNode);
        }
        return true;
    }
    evaluateExpression(plusMinusNudge, node) {
        try {
            return this.api.internalApi
                .getQueryLanguageService()
                .evaluateBooleanExpression(plusMinusNudge.Rule?.BooleanExpression, PlusMinusModuleId, node);
        }
        catch (error) {
            errorOnce(error.message);
            return false;
        }
    }
    ShowErrorPreventMessage(failedRules) {
        if (failedRules.length > 0) {
            let failedMessages = [];
            failedRules.forEach((fr) => {
                let failedMessage = this.api.internalApi.getValidationService().createValidationMessage(fr) + '\n';
                let existingMessage = failedMessages.find((f) => f == failedMessage);
                if (existingMessage == null) {
                    failedMessages.push(failedMessage);
                }
            });
            this.api.alertApi.showAlertError('Nudge(s) failed rule', failedMessages.toString());
        }
    }
    getTeamSharingAction() {
        return {
            ModuleEntities: this.api.plusMinusApi.getAllPlusMinus(),
            AddAction: PlusMinusRedux.PlusMinusNudgeAdd,
            EditAction: PlusMinusRedux.PlusMinusNudgeEdit,
        };
    }
    toView(plusMinus) {
        return {
            abObject: plusMinus,
            items: [
                {
                    name: 'Name',
                    values: [plusMinus.Name],
                },
                {
                    name: 'Target',
                    ...getScopeViewItems(plusMinus.Scope, this.api),
                },
                plusMinus.Rule && {
                    name: 'Settings',
                    label: 'Rule',
                    values: getRuleViewItems(plusMinus.Rule, this.api).values,
                },
                {
                    name: 'Settings',
                    label: 'Nudge Value',
                    values: [plusMinus.NudgeValue],
                },
                getObjectTagsViewItems(plusMinus, this.api),
            ].filter(Boolean),
        };
    }
    toViewAll() {
        return this.getModuleAdaptableObjects({
            includeLayoutNotExtendedObjects: this.showLayoutNonExtendedObjects(),
        }).map((plusMinus) => this.toView(plusMinus));
    }
    getViewProperties() {
        return {
            actions: [MovePlusMinus],
            getEditAction: PlusMinusRedux.PlusMinusNudgeEdit,
            getDeleteAction: PlusMinusRedux.PlusMinusNudgeDelete,
            getSuspendAction: PlusMinusRedux.PlusMinusNudgeSuspend,
            getUnSuspendAction: PlusMinusRedux.PlusMinusNudgeUnSuspend,
            getSuspendAllAction: PlusMinusRedux.PlusMinusNudgeSuspendAll,
            getUnSuspendAllAction: PlusMinusRedux.PlusMinusNudgeUnSuspendAll,
            getEditWizard() {
                return PlusMinusWizard;
            },
        };
    }
    containsLayoutExtensions() {
        return true;
    }
}
