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, useRef } from 'react';
import { observer } from 'mobx-react-lite';
import { CORE_DND_TYPE, TypeDragSource, } from '../../../../stores/editor/utils/DnDUtils.js';
import { MappingEditorState, } from '../../../../stores/editor/editor-state/element-editor-state/mapping/MappingEditorState.js';
import { clsx, CustomSelectorInput, ArrowCircleRightIcon, } from '@finos/legend-art';
import { useDrop } from 'react-dnd';
import { useEditorStore } from '../../EditorStoreProvider.js';
import { Enumeration, EnumerationMapping, DerivedProperty, getEnumerationMappingsByEnumeration, getRawGenericType, EnumerationMappingExplicitReference, } from '@finos/legend-graph';
import { purePropertyMapping_setTransformer } from '../../../../stores/graph-modifier/DSL_Mapping_GraphModifierHelper.js';
import { getExpectedReturnType } from './PropertyMappingsEditor.js';
import { CLASS_PROPERTY_TYPE, getClassPropertyType, } from '../../../../stores/editor/utils/ModelClassifierUtils.js';
import { InlineLambdaEditor } from '@finos/legend-query-builder';
const SimplePropertyMappingEditor = observer((props) => {
    const { propertyMappingState, transformProps, dropConnector, dragItem } = props;
    const ref = useRef(null);
    dropConnector?.(ref);
    const propertyMapping = propertyMappingState.propertyMapping;
    const expectedType = propertyMapping.property.value.genericType.value.rawType;
    const canDrop = dragItem?.data?.type === expectedType;
    const onExpectedTypeLabelSelect = () => propertyMappingState.instanceSetImplementationState.setSelectedType(expectedType);
    const matchedExpectedTypeLabel = () => Boolean(expectedType) &&
        propertyMappingState.instanceSetImplementationState.selectedType ===
            expectedType;
    return (_jsx("div", { className: "property-mapping-editor__entry__container", children: _jsx("div", { ref: ref, className: "property-mapping-editor__entry", children: _jsx(InlineLambdaEditor, { className: clsx({ 'lambda-editor--dnd-match': canDrop }), disabled: transformProps.disableTransform, lambdaEditorState: propertyMappingState, forceBackdrop: transformProps.forceBackdrop, expectedType: expectedType, onExpectedTypeLabelSelect: onExpectedTypeLabelSelect, matchedExpectedType: matchedExpectedTypeLabel }) }) }));
});
const EnumerationPropertyMappingEditor = observer((props) => {
    const { propertyMappingState, dropConnector, dragItem, dragItemType, transformProps, isReadOnly, } = props;
    const editorStore = useEditorStore();
    const mappingEditorState = editorStore.tabManagerState.getCurrentEditorState(MappingEditorState);
    const propertyMapping = propertyMappingState.propertyMapping;
    const enumeration = getRawGenericType(propertyMapping.property.value.genericType.value, Enumeration);
    const expectedType = propertyMapping.transformer?.value.sourceType?.value ?? enumeration;
    const onExpectedTypeLabelSelect = () => propertyMappingState.instanceSetImplementationState.setSelectedType(expectedType);
    const matchedExpectedTypeLabel = () => Boolean(expectedType) &&
        propertyMappingState.instanceSetImplementationState.selectedType ===
            expectedType;
    // Enumeration Mapping Selector
    const options = getEnumerationMappingsByEnumeration(mappingEditorState.mapping, enumeration).map((em) => ({ value: em, label: em.id.value }));
    const handleSelectionChange = (val) => purePropertyMapping_setTransformer(propertyMapping, val?.value
        ? EnumerationMappingExplicitReference.create(val.value)
        : undefined);
    // Walker
    const visit = () => {
        const currentTransformerEnumerationMapping = propertyMapping.transformer?.value;
        if (currentTransformerEnumerationMapping) {
            mappingEditorState.openMappingElement(currentTransformerEnumerationMapping, true);
        }
        else {
            if (!isReadOnly) {
                mappingEditorState.createMappingElement({
                    target: enumeration,
                    showTarget: false,
                    openInAdjacentTab: true,
                    postSubmitAction: (newEnumerationMapping) => {
                        if (newEnumerationMapping instanceof EnumerationMapping) {
                            purePropertyMapping_setTransformer(propertyMapping, EnumerationMappingExplicitReference.create(newEnumerationMapping));
                        }
                    },
                });
            }
        }
    };
    // DnD
    const ref = useRef(null);
    dropConnector?.(ref);
    // NOTE: when we drag enum, we should highlight if the enumeration where that enum is part of matches
    const canDrop = dragItem &&
        ((dragItem.data?.type && dragItem.data.type === expectedType) ||
            (dragItemType === CORE_DND_TYPE.TYPE_TREE_ENUM &&
                dragItem.data?.parent === expectedType));
    return (_jsx("div", { className: "property-mapping-editor__entry__container", children: _jsxs("div", { ref: ref, className: "property-mapping-editor__entry", children: [_jsxs("div", { className: "property-mapping-editor__entry__enumeration-mapping-selector", children: [_jsx(CustomSelectorInput, { disabled: options.length <= 1 || isReadOnly, options: options, onChange: handleSelectionChange, value: propertyMapping.transformer
                                ? {
                                    label: propertyMapping.transformer.valueForSerialization ?? '',
                                    value: propertyMapping.transformer.value,
                                }
                                : null, placeholder: "Choose an existing enumeration mapping" }), _jsx("button", { className: "property-mapping-editor__entry__visit-btn", onClick: visit, tabIndex: -1, title: "Visit enumeration mapping", children: _jsx(ArrowCircleRightIcon, {}) })] }), _jsx(InlineLambdaEditor, { className: clsx('property-mapping-editor__entry__enumeration__transform', { 'lambda-editor--dnd-match': canDrop }), disabled: transformProps.disableTransform, lambdaEditorState: propertyMappingState, forceBackdrop: transformProps.forceBackdrop, expectedType: expectedType, onExpectedTypeLabelSelect: onExpectedTypeLabelSelect, matchedExpectedType: matchedExpectedTypeLabel })] }) }));
});
const ClassPropertyMappingEditor = observer((props) => {
    const { propertyMappingState, dropConnector, dragItem, transformProps } = props;
    const editorStore = useEditorStore();
    const mappingEditorState = editorStore.tabManagerState.getCurrentEditorState(MappingEditorState);
    const propertyMapping = propertyMappingState.propertyMapping;
    const isDefaultId = propertyMapping.targetSetImplementation?.value.id.isDefault;
    const target = isDefaultId ? (_jsx("div", { className: "property-mapping-editor__entry__id__label__default-badge", children: "default" })) : (propertyMapping.targetSetImplementation?.value.id.value);
    const expectedType = getExpectedReturnType(propertyMapping.targetSetImplementation?.value);
    const onExpectedTypeLabelSelect = () => propertyMappingState.instanceSetImplementationState.setSelectedType(expectedType);
    const matchedExpectedTypeLabel = () => Boolean(expectedType) &&
        propertyMappingState.instanceSetImplementationState.selectedType ===
            expectedType;
    // Walker
    const visit = () => {
        if (propertyMapping.targetSetImplementation?.value) {
            mappingEditorState.openMappingElement(propertyMapping.targetSetImplementation.value, true);
        }
    };
    // Drag and Drop
    const ref = useRef(null);
    dropConnector?.(ref);
    const canDrop = dragItem?.data?.type && dragItem.data.type === expectedType;
    return (_jsx("div", { className: "property-mapping-editor__entry__container", children: _jsxs("div", { ref: ref, className: "property-mapping-editor__entry", children: [_jsxs("div", { className: "property-mapping-editor__entry__id", children: [_jsx("div", { className: clsx('property-mapping-editor__entry__id__label', {
                                'property-mapping-editor__entry__id__label--default': isDefaultId,
                            }), children: target }), _jsx("button", { className: "property-mapping-editor__entry__visit-btn", onClick: visit, tabIndex: -1, title: "Visit class mapping", children: _jsx(ArrowCircleRightIcon, {}) })] }), _jsx(InlineLambdaEditor, { className: clsx({ 'lambda-editor--dnd-match': canDrop }), disabled: transformProps.disableTransform, lambdaEditorState: propertyMappingState, forceBackdrop: transformProps.forceBackdrop, expectedType: expectedType, onExpectedTypeLabelSelect: onExpectedTypeLabelSelect, matchedExpectedType: matchedExpectedTypeLabel })] }) }));
});
export const PurePropertyMappingEditor = observer((props) => {
    const { purePropertyMappingState, pureInstanceSetImplementationState, setImplementationHasParserError, isReadOnly, } = props;
    const disableEditingTransform = pureInstanceSetImplementationState.isConvertingTransformLambdaObjects ||
        isReadOnly;
    // DnD
    const handleDrop = useCallback((dropItem, dropType) => {
        if (!disableEditingTransform) {
            if (dropItem instanceof TypeDragSource) {
                // if the dragged node is enum, when dropped, we want to have it as a constant
                let toAppend = '';
                if (dropType === CORE_DND_TYPE.TYPE_TREE_ENUM) {
                    toAppend = `${dropItem.data?.parent.path}.${dropItem.data?.label}`;
                }
                else {
                    if (dropItem.data?.id) {
                        toAppend = dropItem.data.id;
                    }
                    if (dropItem.data?.property instanceof DerivedProperty) {
                        toAppend += '()';
                    }
                }
                if (toAppend) {
                    purePropertyMappingState.setLambdaString(purePropertyMappingState.lambdaString + toAppend);
                }
            }
        }
    }, [disableEditingTransform, purePropertyMappingState]);
    const [{ dragItem, dragItemType }, dropConnector] = useDrop(() => ({
        accept: [
            CORE_DND_TYPE.TYPE_TREE_CLASS,
            CORE_DND_TYPE.TYPE_TREE_ENUMERATION,
            CORE_DND_TYPE.TYPE_TREE_PRIMITIVE,
            CORE_DND_TYPE.TYPE_TREE_ENUM,
        ],
        drop: (item, monitor) => handleDrop(item, monitor.getItemType()),
        collect: (monitor) => ({
            dragItem: monitor.getItem() ?? undefined,
            dragItemType: monitor.getItemType(),
        }),
    }), [handleDrop]);
    const transformProps = {
        disableTransform: disableEditingTransform,
        forceBackdrop: setImplementationHasParserError,
    };
    switch (getClassPropertyType(purePropertyMappingState.propertyMapping.property.value.genericType
        .value.rawType)) {
        case CLASS_PROPERTY_TYPE.UNIT:
        case CLASS_PROPERTY_TYPE.MEASURE:
        case CLASS_PROPERTY_TYPE.PRIMITIVE:
            return (_jsx(SimplePropertyMappingEditor, { propertyMappingState: purePropertyMappingState, dropConnector: dropConnector, dragItem: dragItem, transformProps: transformProps, isReadOnly: isReadOnly }));
        case CLASS_PROPERTY_TYPE.ENUMERATION:
            return (_jsx(EnumerationPropertyMappingEditor, { propertyMappingState: purePropertyMappingState, dropConnector: dropConnector, dragItem: dragItem, dragItemType: dragItemType, transformProps: transformProps, isReadOnly: isReadOnly }));
        case CLASS_PROPERTY_TYPE.CLASS:
            return (_jsx(ClassPropertyMappingEditor, { propertyMappingState: purePropertyMappingState, dropConnector: dropConnector, dragItem: dragItem, transformProps: transformProps, isReadOnly: isReadOnly }));
        default:
            return null;
    }
});
//# sourceMappingURL=PurePropertyMappingEditor.js.map