import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/**
 * 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 { useCallback, useEffect, useRef, useState, } from 'react';
import { clsx, Dialog, PanelDropZone, InfoCircleIcon, Modal, ModalHeader, ModalBody, ModalFooter, ModalFooterButton, InputWithInlineValidation, } from '@finos/legend-art';
import { observer } from 'mobx-react-lite';
import { generateValueSpecificationForParameter, getPropertyChainName, } from '../stores/QueryBuilderPropertyEditorState.js';
import { useDrop } from 'react-dnd';
import { Class, Enumeration, PrimitiveType, isSuperType, AbstractPropertyExpression, INTERNAL__PropagatedValue, getMilestoneTemporalStereotype, } from '@finos/legend-graph';
import { guaranteeNonNullable, guaranteeType } from '@finos/legend-shared';
import { BasicValueSpecificationEditor, QUERY_BUILDER_VARIABLE_DND_TYPE, } from './shared/BasicValueSpecificationEditor.js';
import { functionExpression_setParameterValue } from '../stores/shared/ValueSpecificationModifierHelper.js';
import { ActionAlertActionType, ActionAlertType, } from '@finos/legend-application';
import { VariableSelector } from './shared/QueryBuilderVariableSelector.js';
import { generateMilestonedPropertyParameterValue, isDefaultDatePropagationSupported, matchMilestoningParameterValue, } from '../stores/milestoning/QueryBuilderMilestoningHelper.js';
const DerivedPropertyParameterValueEditor = observer((props) => {
    const { derivedPropertyExpressionState, variable, idx } = props;
    const graph = derivedPropertyExpressionState.queryBuilderState.graphManagerState.graph;
    const parameterType = guaranteeNonNullable(derivedPropertyExpressionState.parameters[idx]?.genericType).value.rawType;
    const handleDrop = useCallback((item) => {
        functionExpression_setParameterValue(derivedPropertyExpressionState.propertyExpression, item.variable, idx + 1, derivedPropertyExpressionState.queryBuilderState.observerContext);
    }, [derivedPropertyExpressionState, idx]);
    const [{ isParameterValueDragOver }, dropConnector] = useDrop(() => ({
        accept: [QUERY_BUILDER_VARIABLE_DND_TYPE],
        drop: (item, monitor) => {
            const itemType = item.variable.genericType?.value.rawType;
            if (!monitor.didDrop() &&
                // Doing a type check, which only allows dragging and dropping parameters of the same type or of child types
                itemType &&
                (isSuperType(parameterType, itemType) ||
                    parameterType.name === itemType.name)) {
                handleDrop(item);
            } // prevent drop event propagation to accomondate for nested DnD
        },
        collect: (monitor) => ({
            isParameterValueDragOver: monitor.isOver({
                shallow: true,
            }),
        }),
    }), [handleDrop]);
    const queryBuilderState = derivedPropertyExpressionState.queryBuilderState;
    // Resets the next property expression in the property chain for milestoned properties when the user changes
    // the milestoned dates of current property expression and it propagates those dates to next property expression.
    const resetNextExpression = (nextExpression) => {
        const milestoningStereotype = getMilestoneTemporalStereotype(guaranteeType(nextExpression.func.value.genericType.value.rawType, Class), queryBuilderState.graphManagerState.graph);
        nextExpression.parametersValues.slice(1).forEach((parameter, index) => {
            if (milestoningStereotype &&
                parameter instanceof INTERNAL__PropagatedValue &&
                !matchMilestoningParameterValue(milestoningStereotype, index, parameter.getValue(), queryBuilderState.milestoningState)) {
                const newParameterValue = new INTERNAL__PropagatedValue(() => guaranteeNonNullable(queryBuilderState.milestoningState
                    .getMilestoningImplementation(milestoningStereotype)
                    .getMilestoningDate(index)));
                newParameterValue.isPropagatedValue = false;
                functionExpression_setParameterValue(guaranteeType(nextExpression, AbstractPropertyExpression), guaranteeNonNullable(newParameterValue), index + 1, queryBuilderState.observerContext);
            }
        });
    };
    const checkDatePropagation = (nextExpression) => {
        if (nextExpression instanceof AbstractPropertyExpression &&
            isDefaultDatePropagationSupported(nextExpression, queryBuilderState) &&
            nextExpression.func.value.genericType.value.rawType instanceof Class) {
            queryBuilderState.applicationStore.alertService.setActionAlertInfo({
                message: 'You have just changed a milestoning date in the property expression chain, this date will be propagated down the rest of the chain. Do you want to proceed? Otherwise, you can choose to propagate the default milestoning dates instead.',
                type: ActionAlertType.CAUTION,
                actions: [
                    {
                        label: 'Proceed',
                        type: ActionAlertActionType.PROCEED_WITH_CAUTION,
                        default: true,
                    },
                    {
                        label: 'Propagate default milestoning date(s)',
                        type: ActionAlertActionType.PROCEED,
                        handler: queryBuilderState.applicationStore.guardUnhandledError(async () => resetNextExpression(nextExpression)),
                    },
                ],
            });
        }
    };
    const resetParameterValue = () => {
        functionExpression_setParameterValue(derivedPropertyExpressionState.propertyExpression, generateMilestonedPropertyParameterValue(derivedPropertyExpressionState, idx) ??
            generateValueSpecificationForParameter(variable, derivedPropertyExpressionState.queryBuilderState.graphManagerState
                .graph, derivedPropertyExpressionState.queryBuilderState
                .INTERNAL__enableInitializingDefaultSimpleExpressionValue, derivedPropertyExpressionState.queryBuilderState.observerContext), idx + 1, derivedPropertyExpressionState.queryBuilderState.observerContext);
        const derivedPropertyExpressionStates = derivedPropertyExpressionState.propertyExpressionState
            .derivedPropertyExpressionStates;
        const currentDerivedPropertyStateindex = derivedPropertyExpressionStates.indexOf(derivedPropertyExpressionState);
        checkDatePropagation(currentDerivedPropertyStateindex + 1 <
            derivedPropertyExpressionStates.length
            ? derivedPropertyExpressionStates[currentDerivedPropertyStateindex + 1]?.propertyExpression
            : undefined);
    };
    const valueSpec = guaranteeNonNullable(derivedPropertyExpressionState.parameterValues[idx]);
    return (_jsxs("div", { className: "panel__content__form__section", children: [_jsx("div", { className: "panel__content__form__section__header__label", children: variable.name }), _jsx("div", { className: "panel__content__form__section__header__prompt", children: `${variable.multiplicity.lowerBound === 0 ? 'optional' : ''}` }), _jsx("div", { className: "query-builder__variable-editor", children: _jsx(PanelDropZone, { isDragOver: isParameterValueDragOver, dropTargetConnector: dropConnector, children: _jsx(BasicValueSpecificationEditor, { valueSpecification: valueSpec, setValueSpecification: (val) => {
                            functionExpression_setParameterValue(derivedPropertyExpressionState.propertyExpression, val, idx + 1, derivedPropertyExpressionState.queryBuilderState
                                .observerContext);
                        }, graph: graph, observerContext: derivedPropertyExpressionState.queryBuilderState.observerContext, typeCheckOption: {
                            expectedType: parameterType,
                            match: parameterType === PrimitiveType.DATETIME,
                        }, resetValue: resetParameterValue, isConstant: queryBuilderState.constantState.isValueSpecConstant(valueSpec) }) }) }), _jsx("div", { className: "panel__content__form__section__list" })] }, variable.name));
});
const DerivedPropertyExpressionEditor = observer((props) => {
    const { derivedPropertyExpressionState } = props;
    const parameterValues = derivedPropertyExpressionState.parameterValues;
    const parameters = derivedPropertyExpressionState.parameters;
    return (_jsxs("div", { className: "query-builder-property-editor__section", children: [_jsx("div", { className: "panel__content__form__section__header__label", children: derivedPropertyExpressionState.title }), !parameterValues.length && (_jsx("div", { className: "query-builder-property-editor__section__content--empty", children: "No parameter" })), parameters.map((variable, idx) => (_jsx(DerivedPropertyParameterValueEditor, { derivedPropertyExpressionState: derivedPropertyExpressionState, variable: variable, idx: idx }, variable.name)))] }));
});
export const QueryBuilderPropertyExpressionEditor = observer((props) => {
    const { propertyExpressionState } = props;
    const applicationStore = propertyExpressionState.queryBuilderState.applicationStore;
    const handleClose = () => propertyExpressionState.setIsEditingDerivedProperty(false);
    const isParameterCompatibleWithDerivedProperty = (variable, derivedProperties) => Boolean(derivedProperties.find((dp) => {
        const variableType = variable.genericType?.value.rawType;
        if (!variableType) {
            return false;
        }
        return dp.parameters.some((p) => p.genericType &&
            (isSuperType(variableType, p.genericType.value.rawType) ||
                p.genericType.value.rawType.name === variableType.name));
    }));
    return (_jsx(Dialog, { open: Boolean(propertyExpressionState.isEditingDerivedPropertyExpression), onClose: handleClose, classes: {
            root: 'editor-modal__root-container',
            container: 'editor-modal__container',
            paper: 'editor-modal__content',
        }, children: _jsxs(Modal, { darkMode: !applicationStore.layoutService.TEMPORARY__isLightColorThemeEnabled, className: "editor-modal query-builder-property-editor", children: [_jsx(ModalHeader, { title: "Derived Property" }), _jsxs(ModalBody, { className: "query-builder-property-editor__content", children: [propertyExpressionState.derivedPropertyExpressionStates.map((pe) => (_jsx(DerivedPropertyExpressionEditor, { derivedPropertyExpressionState: pe }, pe.path))), _jsx(ModalBody, { className: "query-builder__variables__modal__body", children: _jsx(VariableSelector, { queryBuilderState: propertyExpressionState.queryBuilderState, filterBy: (v) => isParameterCompatibleWithDerivedProperty(v, propertyExpressionState.derivedPropertyExpressionStates) }) })] }), _jsx(ModalFooter, { children: _jsx(ModalFooterButton, { text: "Done", onClick: handleClose }) })] }) }));
});
export const QueryBuilderPropertyNameDisplay = observer((props) => {
    const { columnName, title, error, setIsEditingColumnName } = props;
    return (_jsx("div", { className: "query-builder__property__name__display", title: title, children: _jsx("span", { className: clsx('query-builder__property__name__display__content', {
                'query-builder__property__name__display__content--error': error,
                'editable-value': setIsEditingColumnName,
            }), onClick: () => {
                setIsEditingColumnName?.(true);
            }, children: columnName }) }));
});
export const QueryBuilderEditablePropertyName = observer((props) => {
    const { columnName, setColumnName, error, title, defaultColumnName } = props;
    const [isEditingColumnName, setIsEditingColumnName] = useState(false);
    const [selectedColumnName, setSelectedColumnName] = useState(columnName);
    const columnNameInputRef = useRef(null);
    useEffect(() => {
        if (isEditingColumnName) {
            columnNameInputRef.current?.focus();
        }
    }, [isEditingColumnName, columnNameInputRef]);
    const handleFinishEditing = () => {
        const trimmedSelectedColumnName = selectedColumnName.trim();
        if (trimmedSelectedColumnName.length > 0) {
            setColumnName?.(trimmedSelectedColumnName);
            setSelectedColumnName(trimmedSelectedColumnName);
        }
        else {
            setColumnName?.(defaultColumnName);
            setSelectedColumnName(defaultColumnName);
        }
        setIsEditingColumnName(false);
    };
    return isEditingColumnName ? (_jsx("div", { className: "query-builder__property__name__editor", children: _jsx(InputWithInlineValidation, { className: "query-builder__property__name__editor__input input-group__input", spellCheck: false, value: selectedColumnName, onChange: (event) => setSelectedColumnName(event.target.value), onKeyDown: (event) => {
                if (event.key === 'Enter') {
                    handleFinishEditing();
                }
            }, onBlur: handleFinishEditing, ref: columnNameInputRef, draggable: true, onDragStart: (e) => {
                // The below 2 lines are to allow dragging to select text in the input instead of
                // dragging the draggable element containing the input.
                e.preventDefault();
                e.stopPropagation();
            } }) })) : (_jsx(QueryBuilderPropertyNameDisplay, { columnName: columnName, title: title, error: Boolean(error), setIsEditingColumnName: setColumnName ? setIsEditingColumnName : undefined }));
});
export const QueryBuilderPropertyExpressionBadge = observer((props) => {
    const { columnName, propertyExpressionState, setColumnName, error } = props;
    const type = propertyExpressionState.propertyExpression.func.value.genericType.value
        .rawType;
    const hasDerivedPropertyInExpression = Boolean(propertyExpressionState.derivedPropertyExpressionStates.length);
    const isValid = propertyExpressionState.isValid;
    const setDerivedPropertyArguments = () => {
        if (hasDerivedPropertyInExpression) {
            propertyExpressionState.setIsEditingDerivedProperty(true);
        }
    };
    return (_jsx("div", { className: "query-builder-property-expression-badge", children: _jsxs("div", { className: clsx('query-builder-property-expression-badge__content', {
                'query-builder-property-expression-badge__content--class': type instanceof Class,
                'query-builder-property-expression-badge__content--enumeration': type instanceof Enumeration,
                'query-builder-property-expression-badge__content--primitive': type instanceof PrimitiveType,
            }), children: [_jsx(QueryBuilderEditablePropertyName, { columnName: columnName ?? propertyExpressionState.title, setColumnName: setColumnName, error: error, title: `${propertyExpressionState.title} - ${propertyExpressionState.path}`, defaultColumnName: getPropertyChainName(propertyExpressionState.propertyExpression, propertyExpressionState.queryBuilderState.explorerState
                        .humanizePropertyName) }), hasDerivedPropertyInExpression && (_jsxs("button", { className: clsx('query-builder-property-expression-badge__action', {
                        'query-builder-property-expression-badge__action--error': !isValid,
                    }), tabIndex: -1, onClick: setDerivedPropertyArguments, title: "Set Derived Property Argument(s)...", children: [!isValid && _jsx(InfoCircleIcon, {}), " (...)"] })), _jsx(QueryBuilderPropertyExpressionEditor, { propertyExpressionState: propertyExpressionState })] }) }));
});
//# sourceMappingURL=QueryBuilderPropertyExpressionEditor.js.map