import * as AlertRedux from '../Redux/ActionsReducers/AlertRedux';
import * as InternalRedux from '../Redux/ActionsReducers/InternalRedux';
import { OBSERVABLE_EXPRESSION_ROW_ADDED, OBSERVABLE_EXPRESSION_ROW_REMOVED, } from '../Utilities/Constants/GeneralConstants';
import * as ModuleConstants from '../Utilities/Constants/ModuleConstants';
import { ArrayExtensions } from '../Utilities/Extensions/ArrayExtensions';
import { getObjectTagsViewItems } from '../Utilities/getObjectTagsViewItems';
import { getRuleViewItems } from '../Utilities/getRuleViewItems';
import { getScopeViewItems } from '../Utilities/getScopeViewItems';
import { ActiveAlertsPanelItemLabel } from '../View/Alert/ActiveAlertsPanelItemLabel';
import { AlertEmptyView } from '../View/Alert/AlertEmptyView';
import { AlertStatusPanel } from '../View/Alert/AlertStatusSubPanel';
import { getAlertType } from '../View/Alert/Utilities/getAlertType';
import { AlertWizard } from '../View/Alert/Wizard/AlertWizard';
import { AdaptableModuleBase } from './AdaptableModuleBase';
import { getAlertBehaviourViewItems } from './Utilities/Alert/getAlertBehaviourViewItems';
import { getAlertPreviewViewItems } from './Utilities/Alert/getAlertPreviewViewItems';
import { getAlertTypeViewItems } from './Utilities/Alert/getAlertTypeViewItems';
export class AlertModule extends AdaptableModuleBase {
    isListeningToCellDataChanges;
    constructor(api) {
        super(ModuleConstants.AlertModuleId, ModuleConstants.AlertModuleFriendlyName, 'alert', 'AlertPopup', 'Get notified when things happen in Adaptable that you need to know about', api);
        this.isListeningToCellDataChanges = false;
    }
    onAdaptableReady() {
        this.checkListenToCellDataChanged();
    }
    shouldListenToDataChanges() {
        return ArrayExtensions.IsNotNullOrEmpty(this.api.alertApi.getActiveAlertDefinitions());
    }
    checkListenToCellDataChanged() {
        if (!this.isListeningToCellDataChanges) {
            if (this.shouldListenToDataChanges()) {
                this.setupCellDataChangeListener();
                this.isListeningToCellDataChanges = true;
            }
        }
    }
    setupCellDataChangeListener() {
        this.api.internalApi
            .getDataService()
            .on('CellDataChanged', (cellDataChangedInfo) => {
            let shouldIgnoreChange = false;
            if (cellDataChangedInfo.trigger === 'undo') {
                shouldIgnoreChange = true;
            }
            if (cellDataChangedInfo.trigger === 'aggChange') {
                shouldIgnoreChange = !cellDataChangedInfo.column.isGeneratedPivotResultColumn;
            }
            if (shouldIgnoreChange) {
                // do NOT handle reverted or aggregated changes
                return;
            }
            if (this.api.optionsApi.getAlertOptions().dataChangeDetectionPolicy === 'formattedValue') {
                const { oldValue, newValue, rowNode } = cellDataChangedInfo;
                const columnId = cellDataChangedInfo.column.columnId;
                const oldFormattedValue = this.api.gridApi.getDisplayValueFromRawValue(rowNode, columnId, oldValue);
                const newFormattedValue = this.api.gridApi.getDisplayValueFromRawValue(rowNode, columnId, newValue);
                if (oldFormattedValue === newFormattedValue) {
                    // if the formattedValues are identical, then no alert is fired
                    return;
                }
            }
            this.handleCellDataChanged(cellDataChangedInfo);
        });
        this.api.internalApi
            .getDataService()
            .on('RowDataChanged', (rowDataChangedInfo) => {
            if (rowDataChangedInfo.rowTrigger === 'Update') {
                // changed row alerts should be handled by standard 'AnyChange' Predicate
                return;
            }
            this.handleRowDataChanged(rowDataChangedInfo);
        });
        this.api.internalApi
            .getAlertService()
            .onReactiveAlertTriggered((reactiveAlertInfo) => this.handleReactiveAlertTriggered(reactiveAlertInfo));
        this.api.alertApi.internalApi.setUpReactiveAlerts();
    }
    getModuleAdaptableObjects(config) {
        return this.api.alertApi.getAlertDefinitions(config);
    }
    getExplicitlyReferencedColumnIds(alertDefinition) {
        const queryExpression = this.api.expressionApi.getAdaptableQueryExpression(alertDefinition.Rule);
        if (queryExpression) {
            return this.api.expressionApi.getColumnsFromExpression(queryExpression);
        }
        else if (this.api.columnScopeApi.scopeHasColumns(alertDefinition.Scope)) {
            return this.api.columnScopeApi
                .getColumnsInScope(alertDefinition.Scope)
                .map((adaptableColumn) => adaptableColumn.columnId);
        }
        return [];
    }
    getReferencedNamedQueryNames(alertDefinition) {
        const queryExpression = this.api.expressionApi.getAdaptableQueryExpression(alertDefinition.Rule);
        if (!queryExpression) {
            return [];
        }
        return this.api.namedQueryApi.internalApi.getReferencedNamedQueryNames(queryExpression);
    }
    createContextMenuItems(menuContext) {
        const items = [];
        if (!menuContext.isRowGroupColumn && this.isModuleVisible()) {
            if (menuContext.adaptableColumn && menuContext.rowNode) {
                let relevantAlert;
                // find alerts which highlight the current cell
                relevantAlert = this.api.alertApi.internalApi.getAdaptableAlertWithHighlightCell(menuContext.adaptableColumn.columnId, menuContext.rowNode);
                if (!relevantAlert) {
                    // find alerts which highlight the current row
                    relevantAlert = this.api.alertApi.internalApi.getAdaptableAlertWithHighlightRow(menuContext.rowNode);
                }
                if (relevantAlert) {
                    items.push(this.createMenuItemReduxAction('alert-clear', 'Clear Alert', this.moduleInfo.Glyph, InternalRedux.AdaptableAlertDelete(relevantAlert)));
                }
            }
        }
        return items;
    }
    handleCellDataChanged(cellDataChangedInfo) {
        const alertDefinitions = this.api.alertApi.internalApi.getAlertDefinitionsForCellDataChange(cellDataChangedInfo);
        if (ArrayExtensions.IsNotNullOrEmpty(alertDefinitions)) {
            this.api.alertApi.internalApi.showAlertForDefinitions(cellDataChangedInfo, alertDefinitions);
        }
    }
    handleRowDataChanged(rowDataChangedInfo) {
        const alertDefinitions = this.getAlertDefinitionsForRowDataChange(rowDataChangedInfo);
        this.api.alertApi.internalApi.showAlertsForRowDataChanges(rowDataChangedInfo, alertDefinitions);
    }
    handleReactiveAlertTriggered(reactiveAlertInfo) {
        // TODO  - suppress Notification if alert is not relevant for layout
        if (reactiveAlertInfo.type === 'cellDataChangedAlert') {
            // the row node data is most probably stale because the reactive queries buffer the changed data
            // so we have to refresh it
            reactiveAlertInfo.cellChangeLogEntry.rowNode = this.api.gridApi.getRowNodeForPrimaryKey(reactiveAlertInfo.cellChangeLogEntry.primaryKeyValue);
            reactiveAlertInfo.cellChangeLogEntry.rowData =
                reactiveAlertInfo.cellChangeLogEntry.rowNode?.data;
            this.api.alertApi.internalApi.showAlertForDefinitions(reactiveAlertInfo.cellChangeLogEntry, [
                reactiveAlertInfo.alertDefinition,
            ]);
        }
        else {
            // reactiveAlertInfo.type === rowDataChangedAlert'
            this.api.alertApi.internalApi.showAlertForDefinitions(reactiveAlertInfo.gridChangeLogEntry, [
                reactiveAlertInfo.alertDefinition,
            ]);
        }
    }
    getAlertDefinitionsForRowDataChange(rowDataChangedInfo) {
        return this.api.alertApi.internalApi
            .getActiveNonReactiveAlertDefinitions()
            .filter((alertDefinition) => this.api.alertApi.internalApi.isAlertDefinitionForRowChangeEvent(alertDefinition))
            .filter((alertDefinition) => {
            if (rowDataChangedInfo.rowTrigger === 'Add') {
                return alertDefinition.Rule?.ObservableExpression.includes(OBSERVABLE_EXPRESSION_ROW_ADDED);
            }
            if (rowDataChangedInfo.rowTrigger === 'Delete') {
                return alertDefinition.Rule?.ObservableExpression.includes(OBSERVABLE_EXPRESSION_ROW_REMOVED);
            }
            return false;
        });
    }
    getTeamSharingAction() {
        const config = {
            includeLayoutNotExtendedObjects: false,
        };
        return {
            ModuleEntities: this.api.alertApi.getAlertDefinitions(config),
            AddAction: AlertRedux.AlertDefinitionAdd,
            EditAction: AlertRedux.AlertDefinitionEdit,
        };
    }
    toViewCompact(alert) {
        return {
            item: {
                name: alert.header,
                label: ActiveAlertsPanelItemLabel,
                values: [alert.message],
            },
            abObject: alert,
        };
    }
    toView(alert) {
        const alertType = getAlertType(alert);
        return {
            items: [
                {
                    name: 'Name',
                    values: [alert.Name],
                },
                getAlertTypeViewItems(alert),
                alertType === 'DataChange' && {
                    ...getScopeViewItems(alert.Scope, this.api),
                    label: 'Trigger',
                    name: 'Trigger',
                },
                { ...getRuleViewItems(alert.Rule, this.api), label: 'Rule', name: 'Rule' },
                getAlertBehaviourViewItems(this.api),
                getAlertPreviewViewItems(alert, this.api),
                getObjectTagsViewItems(alert, this.api),
            ].filter(Boolean),
            abObject: alert,
        };
    }
    toViewAll() {
        return this.getModuleAdaptableObjects({
            includeLayoutNotExtendedObjects: this.showLayoutNonExtendedObjects(),
        }).map((alert) => this.toView(alert));
    }
    getViewProperties() {
        return {
            getDeleteAction: AlertRedux.AlertDefinitionDelete,
            getEditAction: AlertRedux.AlertDefinitionEdit,
            getSuspendAction: AlertRedux.AlertDefinitionSuspend,
            getUnSuspendAction: AlertRedux.AlertDefinitionUnSuspend,
            getSuspendAllAction: AlertRedux.AlertDefinitionSuspendAll,
            getUnSuspendAllAction: AlertRedux.AlertDefinitionUnSuspendAll,
            getCompactDeleteAction: InternalRedux.AdaptableAlertDelete,
            getDeleteAllAction: () => {
                const alerts = this.api.internalApi.getState().Internal.AdaptableAlerts;
                return InternalRedux.AdaptableAlertDeleteAll(alerts);
            },
            emptyView: AlertEmptyView,
            getEditWizard: () => AlertWizard,
            getStatusBarPanelProps: () => {
                return {
                    popoverMinWidth: 360,
                    view: AlertStatusPanel,
                };
            },
        };
    }
    containsLayoutExtensions() {
        return true;
    }
}
