import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } 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 { observer } from 'mobx-react-lite';
import { PurePropertyMappingEditor } from './PurePropertyMappingEditor.js';
import { getElementIcon } from '../../../ElementIconUtils.js';
import { MappingEditorState, } from '../../../../stores/editor/editor-state/element-editor-state/mapping/MappingEditorState.js';
import { PurePropertyMappingState, PureInstanceSetImplementationState, } from '../../../../stores/editor/editor-state/element-editor-state/mapping/PureInstanceSetImplementationState.js';
import { clsx, ArrowCircleRightIcon, TimesCircleIcon, TimesIcon, AsteriskIcon, } from '@finos/legend-art';
import { guaranteeType } from '@finos/legend-shared';
import { FlatDataInstanceSetImplementationState, } from '../../../../stores/editor/editor-state/element-editor-state/mapping/FlatDataInstanceSetImplementationState.js';
import { FlatDataPropertyMappingEditor } from './FlatDataPropertyMappingEditor.js';
import { RelationalPropertyMappingEditor } from './relational/RelationalPropertyMappingEditor.js';
import { useEditorStore } from '../../EditorStoreProvider.js';
import { getRootSetImplementation, Class, SetImplementation, PrimitiveType, PureInstanceSetImplementation, EmbeddedFlatDataPropertyMapping, OperationSetImplementation, FlatDataInstanceSetImplementation, RootRelationalInstanceSetImplementation, MULTIPLICITY_INFINITE, RelationFunctionInstanceSetImplementation, } from '@finos/legend-graph';
import { useApplicationStore } from '@finos/legend-application';
import { instanceSetImplementation_deletePropertyMapping, setImpl_nominateRoot, setImplementation_setRoot, } from '../../../../stores/graph-modifier/DSL_Mapping_GraphModifierHelper.js';
import { CLASS_PROPERTY_TYPE, getClassPropertyType, } from '../../../../stores/editor/utils/ModelClassifierUtils.js';
import { Fragment } from 'react';
import { RelationFunctionPropertyMappingEditor } from './RelationFunctionPropertyMappingEditor.js';
const MultiplicityBadge = (props) => {
    const { multiplicity } = props;
    const isRequired = multiplicity.lowerBound && multiplicity.lowerBound > 0;
    const tooltipText = `${isRequired ? '[required]' : '[optional]'}${isRequired ? ` minimum: ${multiplicity.lowerBound}` : ''} maximum: ${multiplicity.upperBound ?? MULTIPLICITY_INFINITE}`;
    return (_jsx("div", { className: `multiplicity-badge ${isRequired ? 'multiplicity-badge--required' : ''}`, title: tooltipText, children: multiplicity.upperBound ? null : _jsx(AsteriskIcon, {}) }));
};
export const getExpectedReturnType = (targetSetImplementation) => {
    if (targetSetImplementation instanceof PureInstanceSetImplementation) {
        return targetSetImplementation.srcClass?.value;
    }
    else if (targetSetImplementation instanceof OperationSetImplementation) {
        return targetSetImplementation.class.value;
    }
    else {
        return undefined;
    }
};
const GenericPropertyMappingEditorEntry = observer((props) => {
    const { children, instanceSetImplementationState, propertyMappingStates, propertyMappingState, propertyBasicType, } = props;
    const removePropertyMapping = (pm) => {
        instanceSetImplementation_deletePropertyMapping(instanceSetImplementationState.mappingElement, pm);
        instanceSetImplementationState.decorate();
    };
    return (_jsxs("div", { className: "property-mapping-editor__generic-entry", children: [children, propertyMappingStates.length > 1 &&
                propertyBasicType !== CLASS_PROPERTY_TYPE.CLASS && (_jsx("button", { className: "property-mapping-editor__generic-entry__remove-btn", onClick: () => removePropertyMapping(propertyMappingState.propertyMapping), tabIndex: -1, title: "Remove", children: _jsx(TimesIcon, {}) }))] }));
});
export const PropertyMappingEditor = observer((props) => {
    const { instanceSetImplementationState, property, isReadOnly } = props;
    const instanceSetImplementation = instanceSetImplementationState.mappingElement;
    const validationErrorMessage = instanceSetImplementation.propertyMappings.filter((pm) => pm.property.value === property).length > 1 && !(property.genericType.value.rawType instanceof Class)
        ? 'Only one property mapping should exist per property of type other than class (e.g. primitive, measure, enumeration)'
        : undefined;
    const editorStore = useEditorStore();
    const applicationStore = useApplicationStore();
    const mappingEditorState = editorStore.tabManagerState.getCurrentEditorState(MappingEditorState);
    const propertyRawType = property.genericType.value.rawType;
    const propertyBasicType = getClassPropertyType(propertyRawType);
    const isEmbedded = instanceSetImplementation._isEmbedded;
    // Parser Error
    const propertyMappingStates = instanceSetImplementationState.propertyMappingStates.filter((pm) => pm.propertyMapping.property.value === property);
    const propertyHasParserError = Boolean(propertyMappingStates.find((pm) => pm.parserError));
    const setImplementationHasParserError = Boolean(instanceSetImplementationState.propertyMappingStates.find((pm) => pm.parserError));
    /**
     * TODO: revisit this behavior now that we have more types of property mapping to support
     * e.g. embedded, target set implementation, etc.
     * See https://github.com/finos/legend-studio/issues/310
     *
     * @modularize
     * TODO: modularize this for other types
     * See https://github.com/finos/legend-studio/issues/65
     */
    const visitOrCreateMappingElement = () => {
        if (propertyRawType instanceof Class) {
            if (instanceSetImplementation instanceof PureInstanceSetImplementation) {
                const rootMappingElement = getRootSetImplementation(mappingEditorState.mapping, propertyRawType);
                if (rootMappingElement) {
                    if (!rootMappingElement.root.value) {
                        setImplementation_setRoot(rootMappingElement, true);
                    }
                    const parent = rootMappingElement._PARENT;
                    if (parent !== mappingEditorState.element) {
                        // TODO: think more about this flow. Right now we open the mapping element in the parent mapping
                        editorStore.graphEditorMode.openElement(parent);
                        editorStore.tabManagerState
                            .getCurrentEditorState(MappingEditorState)
                            .openMappingElement(rootMappingElement, false);
                    }
                    {
                        mappingEditorState.openMappingElement(rootMappingElement, true);
                    }
                }
                else {
                    if (!isReadOnly) {
                        mappingEditorState.createMappingElement({
                            target: property.genericType.value.rawType,
                            showTarget: false,
                            openInAdjacentTab: true,
                            postSubmitAction: (newSetImpl) => {
                                // Make this set implementation the new root
                                if (newSetImpl instanceof SetImplementation) {
                                    setImpl_nominateRoot(newSetImpl);
                                }
                            },
                        });
                    }
                }
            }
            else if (instanceSetImplementationState instanceof
                FlatDataInstanceSetImplementationState) {
                if (propertyMappingStates.length === 1 &&
                    propertyMappingStates[0]?.propertyMapping instanceof
                        EmbeddedFlatDataPropertyMapping) {
                    mappingEditorState.openMappingElement(propertyMappingStates[0].propertyMapping, true);
                }
                else if (!propertyMappingStates.length) {
                    const embedded = instanceSetImplementationState.addEmbeddedPropertyMapping(property);
                    mappingEditorState.openMappingElement(embedded, true);
                }
            }
            else {
                applicationStore.notificationService.notifyWarning(`Can't visit mapping element for type '${propertyRawType.name}'`);
            }
        }
    };
    const renderPropertyMappingEntry = (propertyMappingState) => {
        if (instanceSetImplementation instanceof PureInstanceSetImplementation) {
            return (_jsx(PurePropertyMappingEditor, { isReadOnly: isReadOnly, pureInstanceSetImplementationState: guaranteeType(instanceSetImplementationState, PureInstanceSetImplementationState), purePropertyMappingState: guaranteeType(propertyMappingState, PurePropertyMappingState), setImplementationHasParserError: setImplementationHasParserError }));
        }
        else if (instanceSetImplementation instanceof
            FlatDataInstanceSetImplementation ||
            instanceSetImplementation instanceof EmbeddedFlatDataPropertyMapping) {
            return (_jsx(FlatDataPropertyMappingEditor, { isReadOnly: isReadOnly, flatDataInstanceSetImplementationState: instanceSetImplementationState, flatDataPropertyMappingState: propertyMappingState, setImplementationHasParserError: setImplementationHasParserError }));
        }
        else if (instanceSetImplementation instanceof
            RootRelationalInstanceSetImplementation) {
            return (_jsx(RelationalPropertyMappingEditor, { isReadOnly: isReadOnly, relationalInstanceSetImplementationState: instanceSetImplementationState, relationalPropertyMappingState: propertyMappingState, setImplementationHasParserError: setImplementationHasParserError }));
        }
        else if (instanceSetImplementation instanceof
            RelationFunctionInstanceSetImplementation) {
            return (_jsx(RelationFunctionPropertyMappingEditor, { isReadOnly: isReadOnly, relationInstanceSetImplementationState: instanceSetImplementationState, relationPropertyMappingState: propertyMappingState, setImplementationHasParserError: setImplementationHasParserError }));
        }
        else {
            const extraPropertyMappingEditorRenderers = editorStore.pluginManager
                .getApplicationPlugins()
                .flatMap((plugin) => plugin.getExtraPropertyMappingEditorRenderers?.() ?? []);
            for (const renderer of extraPropertyMappingEditorRenderers) {
                const renderedPropertyMappingEditor = renderer(instanceSetImplementationState, propertyMappingState);
                if (renderedPropertyMappingEditor) {
                    return (_jsx(Fragment, { children: renderedPropertyMappingEditor }, propertyMappingState.uuid));
                }
            }
            return (_jsx("div", { className: "property-mapping-editor__entry--unsupported", children: "Unsupported property mapping" }, propertyMappingState.uuid));
        }
    };
    return (_jsxs("div", { className: clsx('property-mapping-editor', {
            backdrop__element: propertyHasParserError,
        }), children: [_jsxs("div", { className: "property-mapping-editor__metadata", children: [_jsxs("div", { className: clsx('property-mapping-editor__name', {
                            'property-mapping-editor__name--with-validation': Boolean(validationErrorMessage),
                        }), children: [_jsx("div", { className: "property-mapping-editor__name__label", children: property.name }), validationErrorMessage && (_jsx("div", { className: "property-mapping-editor__name--with-validation__indicator", title: validationErrorMessage, children: _jsx(TimesCircleIcon, {}) }))] }), _jsxs("div", { className: "property-mapping-editor__info", children: [_jsxs("div", { className: clsx('property-mapping-editor__type', `background--${propertyBasicType.toLowerCase()}`, {
                                    'property-mapping-editor__type--has-visit-btn': propertyBasicType === CLASS_PROPERTY_TYPE.CLASS,
                                }), title: propertyRawType instanceof PrimitiveType
                                    ? undefined
                                    : propertyRawType.path, children: [propertyBasicType !== CLASS_PROPERTY_TYPE.PRIMITIVE && (_jsx("div", { className: "property-mapping-editor__type__abbr", children: getElementIcon(propertyRawType, editorStore) })), _jsx("div", { className: "property-mapping-editor__type__label", children: propertyRawType.name }), propertyBasicType === CLASS_PROPERTY_TYPE.CLASS && (_jsx("button", { className: "property-mapping-editor__type__visit-btn", onClick: visitOrCreateMappingElement, tabIndex: -1, title: "Visit mapping element", children: _jsx(ArrowCircleRightIcon, {}) }))] }), _jsx("div", { className: "property-mapping-editor__multiplicity", children: _jsx(MultiplicityBadge, { multiplicity: property.multiplicity }) })] })] }), _jsxs("div", { className: "property-mapping-editor__content", children: [propertyMappingStates.map((propertyMappingState) => (_jsx(GenericPropertyMappingEditorEntry, { instanceSetImplementationState: instanceSetImplementationState, propertyBasicType: propertyBasicType, propertyMappingStates: propertyMappingStates, propertyMappingState: propertyMappingState, children: renderPropertyMappingEntry(propertyMappingState) }, propertyMappingState.uuid))), propertyBasicType === CLASS_PROPERTY_TYPE.CLASS &&
                        !propertyMappingStates.length && (_jsxs(_Fragment, { children: [isEmbedded && (_jsxs("div", { className: "property-mapping-editor__entry--empty", children: ["Click", _jsx("button", { className: "property-mapping-editor__entry--empty__visit-btn", onClick: visitOrCreateMappingElement, tabIndex: -1, title: "Create mapping element", children: _jsx(ArrowCircleRightIcon, {}) }), `to create an embedded class mapping for property '${property.name}'.`] })), !isEmbedded && (_jsxs("div", { className: "property-mapping-editor__entry--empty", children: ["No set implementation found. Click", _jsx("button", { className: "property-mapping-editor__entry--empty__visit-btn", onClick: visitOrCreateMappingElement, tabIndex: -1, title: "Create mapping element", children: _jsx(ArrowCircleRightIcon, {}) }), `to create a root class mapping for '${propertyRawType.name}'.`] }))] }))] })] }));
});
//# sourceMappingURL=PropertyMappingsEditor.js.map