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 { useRef, useState, useEffect, useCallback } from 'react';
import { observer } from 'mobx-react-lite';
import { Dialog, ResizablePanel, ResizablePanelGroup, ResizablePanelSplitter, clsx, CustomSelectorInput, BlankPanelPlaceholder, createFilter, PURE_EnumerationIcon, PencilIcon, TimesIcon, PlusIcon, PanelDropZone, Panel, PanelContent, ModalTitle, Modal, PanelHeaderActionItem, PanelHeaderActions, PanelHeader, } from '@finos/legend-art';
import { MappingEditorState } from '../../../../stores/editor/editor-state/element-editor-state/mapping/MappingEditorState.js';
import { TypeTree } from './TypeTree.js';
import { useDrop } from 'react-dnd';
import { CORE_DND_TYPE, TypeDragSource, } from '../../../../stores/editor/utils/DnDUtils.js';
import { LEGEND_STUDIO_TEST_ID } from '../../../../__lib__/LegendStudioTesting.js';
import { noop } from '@finos/legend-shared';
import { MappingElementDecorator, MappingElementDecorationCleaner, } from '../../../../stores/editor/editor-state/element-editor-state/mapping/MappingElementDecorator.js';
import { useEditorStore } from '../../EditorStoreProvider.js';
import { Type, Enum, Enumeration, getEnumValueNames, PackageableElementExplicitReference, PrimitiveType, } from '@finos/legend-graph';
import { enumerationMapping_updateSourceType, enumValueMapping_addSourceValue, enumValueMapping_deleteSourceValue, enumValueMapping_updateSourceValue, } from '../../../../stores/graph-modifier/DSL_Mapping_GraphModifierHelper.js';
import { buildElementOption, getPackageableElementOptionFormatter, } from '@finos/legend-lego/graph-editor';
const EnumerationMappingSourceSelectorModal = observer((props) => {
    const { enumerationMapping, closeModal, open } = props;
    const editorStore = useEditorStore();
    const applicationStore = editorStore.applicationStore;
    const options = [PrimitiveType.INTEGER, PrimitiveType.STRING]
        .map(buildElementOption)
        .concat(editorStore.graphManagerState.usableEnumerations.map(buildElementOption));
    const sourceSelectorRef = useRef(null);
    const filterOption = createFilter({
        ignoreCase: true,
        ignoreAccents: false,
        stringify: (option) => option.data.value.path,
    });
    const sourceType = enumerationMapping.sourceType?.value;
    const selectedSourceType = sourceType
        ? { value: sourceType, label: sourceType.name }
        : null;
    const changeSourceType = (val) => {
        const value = val?.value;
        if (!value || value instanceof Type) {
            enumerationMapping_updateSourceType(enumerationMapping, value ? PackageableElementExplicitReference.create(value) : undefined);
        }
        if (value) {
            closeModal();
        }
    };
    const handleEnter = () => sourceSelectorRef.current?.focus();
    return (_jsx(Dialog, { open: open, onClose: closeModal, classes: {
            container: 'search-modal__container',
        }, slotProps: {
            transition: {
                onEnter: handleEnter,
            },
            paper: {
                classes: {
                    root: 'search-modal__inner-container',
                },
            },
        }, children: _jsxs(Modal, { className: "search-modal", darkMode: !applicationStore.layoutService.TEMPORARY__isLightColorThemeEnabled, children: [_jsx(ModalTitle, { title: "Choose a Source" }), _jsx(CustomSelectorInput, { inputRef: sourceSelectorRef, options: options, onChange: changeSourceType, value: selectedSourceType, placeholder: "Choose a type...", isClearable: true, darkMode: !applicationStore.layoutService
                        .TEMPORARY__isLightColorThemeEnabled, filterOption: filterOption, formatOptionLabel: getPackageableElementOptionFormatter({}) })] }) }));
});
export const SourceValueInput = observer((props) => {
    const { sourceValue, updateSourceValue, deleteSourceValue, expectedType, isReadOnly, } = props;
    const value = sourceValue.value instanceof Enum
        ? sourceValue.value.name
        : (sourceValue.value ?? '');
    const onChange = (event) => updateSourceValue(event.target.value);
    const onBlur = (event) => {
        const val = event.target.value;
        // Small validation if sourceType is enumeration
        // reset if not an enum value set to enum if source value not an enum
        if (expectedType instanceof Enumeration &&
            !getEnumValueNames(expectedType).includes(val)) {
            updateSourceValue(undefined);
        }
        else if (expectedType instanceof Enumeration &&
            !(sourceValue instanceof Enum) &&
            getEnumValueNames(expectedType).includes(val)) {
            const enumValue = expectedType.values.find((e) => e.name === val);
            updateSourceValue(enumValue);
        }
    };
    // Drag and Drop
    const handleDrop = useCallback((item) => {
        if (!isReadOnly) {
            if (item instanceof TypeDragSource && item.data) {
                updateSourceValue(value + item.data.label);
            }
        }
    }, [isReadOnly, updateSourceValue, value]);
    const [{ canDrop }, dropConnector] = useDrop(() => ({
        accept: CORE_DND_TYPE.TYPE_TREE_ENUM,
        drop: (item) => handleDrop(item),
        collect: (monitor) => ({
            canDrop: monitor.canDrop(),
        }),
    }), [handleDrop]);
    const ref = useRef(null);
    dropConnector(ref);
    return (_jsxs("div", { ref: ref, className: clsx('enumeration-mapping-editor__enum-value__source-value', {
            'enumeration-mapping-editor__enum-value__source-value--dnd-match': canDrop && !isReadOnly,
        }), children: [_jsx("input", { className: "enumeration-mapping-editor__enum-value__source-value__input", disabled: isReadOnly, spellCheck: false, value: value, onChange: onChange, onBlur: onBlur, placeholder: "Source value", type: expectedType === PrimitiveType.INTEGER ? 'number' : 'text' }), _jsx("div", { className: "enumeration-mapping-editor__enum-value__source-value__info", children: _jsx("div", { className: "enumeration-mapping-editor__enum-value__source-value__expected-return-type", children: expectedType?.name ?? 'unknown' }) }), !isReadOnly && (_jsx("button", { className: "btn--icon enumeration-mapping-editor__enum-value__source-value__remove-btn", disabled: isReadOnly, onClick: deleteSourceValue, tabIndex: -1, title: "Remove", children: _jsx(TimesIcon, {}) }))] }));
});
const EnumValueMappingEditor = observer((props) => {
    const { enumValue, enumerationMapping, sourceType, isReadOnly } = props;
    const matchingEnumValueMapping = enumerationMapping.enumValueMappings.find((evm) => evm.enum.value === enumValue);
    const addSourceValue = () => matchingEnumValueMapping
        ? enumValueMapping_addSourceValue(matchingEnumValueMapping, undefined)
        : undefined;
    return (_jsxs("div", { className: "enumeration-mapping-editor__enum-value", children: [_jsxs("div", { className: "enumeration-mapping-editor__enum-value__metadata", children: [_jsx("div", { className: "enumeration-mapping-editor__enum-value__name", children: enumValue.name }), matchingEnumValueMapping && (_jsx("button", { className: "enumeration-mapping-editor__enum-value__add-btn", disabled: isReadOnly, onClick: addSourceValue, tabIndex: -1, title: "Add enum value", children: _jsx(PlusIcon, {}) }))] }), matchingEnumValueMapping && (_jsxs("div", { children: [matchingEnumValueMapping.sourceValues.map((sourceValue, idx) => (_jsx(SourceValueInput, { isReadOnly: isReadOnly, sourceValue: sourceValue, expectedType: sourceType?.value, updateSourceValue: (val) => enumValueMapping_updateSourceValue(matchingEnumValueMapping, idx, val, sourceType?.value), deleteSourceValue: () => enumValueMapping_deleteSourceValue(matchingEnumValueMapping, idx) }, sourceValue._UUID))), !matchingEnumValueMapping.sourceValues.length && (_jsxs("div", { className: "enumeration-mapping-editor__enum-value__source-value--empty", children: ["No source value. Click", ' ', _jsx("div", { className: "enumeration-mapping-editor__enum-value__source-value--empty__add-btn", onClick: addSourceValue, children: _jsx(PlusIcon, {}) }), ' ', "to add one."] }))] }))] }));
});
export const EnumerationMappingEditor = observer((props) => {
    const { enumerationMapping, isReadOnly } = props;
    const editorStore = useEditorStore();
    const mappingEditorState = editorStore.tabManagerState.getCurrentEditorState(MappingEditorState);
    const enumeration = enumerationMapping.enumeration;
    // ID
    const showId = Object.keys(mappingEditorState.mappingElementsWithSimilarTarget).length >
        1;
    // Source
    const sourceType = enumerationMapping.sourceType?.value;
    const [openSourceSelectorModal, setOpenSourceSelectorModal] = useState(false);
    const showSourceSelectorModal = () => isReadOnly ? undefined : setOpenSourceSelectorModal(true);
    const hideSourceSelectorModal = () => setOpenSourceSelectorModal(false);
    const handleDrop = useCallback((item) => {
        if (!isReadOnly && item.data.packageableElement instanceof Type) {
            enumerationMapping_updateSourceType(enumerationMapping, PackageableElementExplicitReference.create(item.data.packageableElement));
        }
    }, [enumerationMapping, isReadOnly]);
    const [{ isDragOver, canDrop }, dropConnector] = useDrop(() => ({
        accept: CORE_DND_TYPE.PROJECT_EXPLORER_ENUMERATION,
        drop: (item) => handleDrop(item),
        collect: (monitor) => ({
            isDragOver: monitor.isOver({ shallow: true }),
            canDrop: monitor.canDrop(),
        }),
    }), [handleDrop]);
    useEffect(() => {
        if (!isReadOnly) {
            new MappingElementDecorator(editorStore).visitEnumerationMapping(enumerationMapping);
        }
        return isReadOnly
            ? noop()
            : () => new MappingElementDecorationCleaner(editorStore).visitEnumerationMapping(enumerationMapping);
    }, [enumerationMapping, isReadOnly, editorStore]);
    return (_jsxs("div", { className: "mapping-element-editor enumeration-mapping-editor", "data-testid": LEGEND_STUDIO_TEST_ID.ENUMERATION_MAPPING_EDITOR, children: [_jsxs("div", { className: "mapping-element-editor__metadata", children: [_jsxs("div", { className: "mapping-element-editor__metadata__chunk mapping-element-editor__metadata__overview-chunk background--enumeration", children: [_jsx("div", { className: "mapping-element-editor__metadata__sub-chunk", children: "enumeration mapping" }), showId && (_jsx("div", { className: "mapping-element-editor__metadata__sub-chunk mapping-element-editor__metadata__overview__id", children: enumerationMapping.id.isDefault
                                    ? 'default ID'
                                    : enumerationMapping.id.value })), _jsx("div", { className: "mapping-element-editor__metadata__sub-chunk", children: "for" }), _jsxs("div", { className: "mapping-element-editor__metadata__sub-chunk mapping-element-editor__metadata__target", children: [_jsx("div", { className: "mapping-element-editor__metadata__target__type icon", children: _jsx(PURE_EnumerationIcon, {}) }), _jsx("div", { className: "mapping-element-editor__metadata__target__label", children: enumeration.value.name })] })] }), sourceType && (_jsxs("div", { className: clsx('mapping-element-editor__metadata__chunk', 'mapping-element-editor__metadata__driver-chunk', 'background--primitive', 'mapping-element-editor__metadata__source-chunk--primitive', {
                            'mapping-element-editor__metadata__source-chunk--none': !sourceType,
                        }), children: [_jsx("div", { className: "mapping-element-editor__metadata__sub-chunk", children: "using" }), _jsx("div", { className: "mapping-element-editor__metadata__sub-chunk mapping-element-editor__metadata__driver__type", children: sourceType.name })] })), !sourceType && (_jsx("div", { className: clsx('mapping-element-editor__metadata__chunk', 'mapping-element-editor__metadata__source-chunk', 'mapping-element-editor__metadata__source-chunk--none'), children: _jsx("div", { className: "mapping-element-editor__metadata__sub-chunk", children: "with no source" }) }))] }), _jsx("div", { className: "mapping-element-editor__content", children: _jsxs(ResizablePanelGroup, { orientation: "vertical", children: [_jsx(ResizablePanel, { minSize: 300, children: _jsxs(Panel, { children: [_jsx("div", { className: "panel__header", children: _jsx("div", { className: "panel__header__title", children: _jsx("div", { className: "panel__header__title__content", children: "ENUMS" }) }) }), _jsx("div", { className: "panel__content enumeration-mapping-editor__enum-values", children: enumeration.value.values.map((enumValue) => (_jsx(EnumValueMappingEditor, { enumValue: enumValue, enumerationMapping: enumerationMapping, sourceType: enumerationMapping.sourceType, isReadOnly: isReadOnly }, enumValue.name))) })] }) }), _jsx(ResizablePanelSplitter, {}), _jsx(ResizablePanel, { size: 300, minSize: 300, children: _jsxs("div", { "data-testid": LEGEND_STUDIO_TEST_ID.SOURCE_PANEL, className: "panel source-panel", children: [_jsxs(PanelHeader, { children: [_jsxs("div", { className: "panel__header__title", children: [_jsx("div", { className: "panel__header__title__label", children: "source" }), _jsx("div", { className: "panel__header__title__content", children: sourceType?.name ?? '(none)' })] }), _jsx(PanelHeaderActions, { children: _jsx(PanelHeaderActionItem, { onClick: showSourceSelectorModal, disabled: isReadOnly, title: "Choose a source...", children: _jsx(PencilIcon, {}) }) })] }), _jsx(PanelContent, { children: _jsxs(PanelDropZone, { dropTargetConnector: dropConnector, isDragOver: Boolean(sourceType) && isDragOver && !isReadOnly, children: [sourceType && (_jsx("div", { className: "source-panel__explorer", children: sourceType instanceof Enumeration && (_jsx(TypeTree, { type: sourceType })) })), !sourceType && (_jsx(BlankPanelPlaceholder, { text: "Choose a source", onClick: showSourceSelectorModal, clickActionType: "add", tooltipText: "Drop an enumeration", isDropZoneActive: canDrop, disabled: isReadOnly, previewText: "No source" })), _jsx(EnumerationMappingSourceSelectorModal, { enumerationMapping: enumerationMapping, open: openSourceSelectorModal, closeModal: hideSourceSelectorModal })] }) })] }) })] }) })] }));
});
//# sourceMappingURL=EnumerationMappingEditor.js.map