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 { useState, useEffect, useCallback } from 'react';
import { observer } from 'mobx-react-lite';
import { MAPPING_TEST_EDITOR_TAB_TYPE, TEST_RESULT, MappingTestObjectInputDataState, MappingTestFlatDataInputDataState, MappingTestExpectedOutputAssertionState, MappingTestRelationalInputDataState, } from '../../../../../stores/editor/editor-state/element-editor-state/mapping/legacy/DEPRECATED__MappingTestState.js';
import { clsx, PanelLoadingIndicator, BlankPanelPlaceholder, PlayIcon, ResizablePanelGroup, ResizablePanel, ResizablePanelSplitter, ResizablePanelSplitterLine, ControlledDropdownMenu, MenuContent, MenuContentItem, CaretDownIcon, ErrorIcon, RefreshIcon, WrenchIcon, PauseCircleIcon, PanelDropZone, PencilIcon, PanelContent, } from '@finos/legend-art';
import { useDrop } from 'react-dnd';
import { CORE_DND_TYPE, } from '../../../../../stores/editor/utils/DnDUtils.js';
import { IllegalStateError, guaranteeType, tryToFormatLosslessJSONString, assertErrorThrown, } from '@finos/legend-shared';
import { useApplicationStore, ActionAlertActionType, ActionAlertType, } from '@finos/legend-application';
import { ClassMappingSelectorModal, getRelationalInputTestDataEditorLanguage, } from '../MappingExecutionBuilder.js';
import { flowResult } from 'mobx';
import { MappingTestStatusIndicator } from '../MappingTestsExplorer.js';
import { getMappingElementSource, getMappingElementTarget, } from '../../../../../stores/editor/editor-state/element-editor-state/mapping/MappingEditorState.js';
import { useEditorStore } from '../../../EditorStoreProvider.js';
import { Class, SetImplementation, OperationSetImplementation, RelationalInputType, stub_RawLambda, isStubbed_RawLambda, DEPRECATED__validate_MappingTestAssert, } from '@finos/legend-graph';
import { flatData_setData } from '../../../../../stores/graph-modifier/STO_FlatData_GraphModifierHelper.js';
import { relationalInputData_setData, relationalInputData_setInputType, } from '../../../../../stores/graph-modifier/STO_Relational_GraphModifierHelper.js';
import { QueryBuilderTextEditorMode, ExecutionPlanViewer, } from '@finos/legend-query-builder';
import { MappingExecutionQueryBuilderState } from '../../../../../stores/editor/editor-state/element-editor-state/mapping/MappingExecutionQueryBuilderState.js';
import { CODE_EDITOR_LANGUAGE } from '@finos/legend-code-editor';
import { CodeEditor, JSONDiffView } from '@finos/legend-lego/code-editor';
const MappingTestQueryEditor = observer((props) => {
    const { testState, isReadOnly } = props;
    const queryState = testState.queryState;
    const editorStore = useEditorStore();
    const applicationStore = useApplicationStore();
    // actions
    const editWithQueryBuilder = (openInTextMode = false) => applicationStore.guardUnhandledError(async () => {
        const embeddedQueryBuilderState = editorStore.embeddedQueryBuilderState;
        await flowResult(embeddedQueryBuilderState.setEmbeddedQueryBuilderConfiguration({
            setupQueryBuilderState: async () => {
                const queryBuilderState = new MappingExecutionQueryBuilderState(embeddedQueryBuilderState.editorStore.applicationStore, embeddedQueryBuilderState.editorStore.graphManagerState, testState.mappingEditorState.mapping, editorStore.applicationStore.config.options.queryBuilderConfig, editorStore.editorMode.getSourceInfo());
                queryBuilderState.initializeWithQuery(testState.queryState.query);
                if (openInTextMode) {
                    queryBuilderState.textEditorState.openModal(QueryBuilderTextEditorMode.TEXT);
                }
                return queryBuilderState;
            },
            actionConfigs: [
                {
                    key: 'save-query-btn',
                    renderer: (queryBuilderState) => {
                        const save = applicationStore.guardUnhandledError(async () => {
                            try {
                                const rawLambda = queryBuilderState.buildQuery();
                                await flowResult(testState.queryState.updateLamba(rawLambda));
                                applicationStore.notificationService.notifySuccess(`Mapping test query is updated`);
                                embeddedQueryBuilderState.setEmbeddedQueryBuilderConfiguration(undefined);
                            }
                            catch (error) {
                                assertErrorThrown(error);
                                applicationStore.notificationService.notifyError(`Can't save query: ${error.message}`);
                            }
                        });
                        return (_jsx("button", { className: "query-builder__dialog__header__custom-action", tabIndex: -1, disabled: isReadOnly, onClick: save, children: "Save Query" }));
                    },
                },
            ],
            disableCompile: isStubbed_RawLambda(testState.queryState.query),
        }));
    });
    // Class mapping selector
    const [openClassMappingSelectorModal, setOpenClassMappingSelectorModal] = useState(false);
    const showClassMappingSelectorModal = () => setOpenClassMappingSelectorModal(true);
    const hideClassMappingSelectorModal = () => setOpenClassMappingSelectorModal(false);
    const changeClassMapping = useCallback((setImplementation) => {
        // do all the necessary updates
        flowResult(queryState.updateLamba(setImplementation
            ? editorStore.graphManagerState.graphManager.createGetAllRawLambda(guaranteeType(getMappingElementTarget(setImplementation), Class))
            : stub_RawLambda())).catch(applicationStore.alertUnhandledError);
        hideClassMappingSelectorModal();
        // Attempt to generate data for input data panel as we pick the class mapping
        if (setImplementation) {
            applicationStore.alertService.setActionAlertInfo({
                message: 'Mapping test input data is already set',
                prompt: 'Do you want to regenerate the input data?',
                type: ActionAlertType.CAUTION,
                actions: [
                    {
                        label: 'Regenerate',
                        type: ActionAlertActionType.PROCEED_WITH_CAUTION,
                        handler: () => testState.setInputDataStateBasedOnSource(getMappingElementSource(setImplementation, editorStore.pluginManager.getApplicationPlugins()), true),
                    },
                    {
                        label: 'Keep my input data',
                        type: ActionAlertActionType.PROCEED,
                        default: true,
                    },
                ],
            });
        }
    }, [applicationStore, editorStore, testState, queryState]);
    // Drag and Drop
    const handleDrop = useCallback((item) => {
        changeClassMapping(guaranteeType(item.data, SetImplementation));
    }, [changeClassMapping]);
    const [{ isDragOver, canDrop }, dropConnector] = useDrop(() => ({
        accept: CORE_DND_TYPE.MAPPING_EXPLORER_CLASS_MAPPING,
        drop: (item) => handleDrop(item),
        collect: (monitor) => ({
            isDragOver: monitor.isOver({ shallow: true }),
            canDrop: monitor.canDrop(),
        }),
    }), [handleDrop]);
    const clearQuery = applicationStore.guardUnhandledError(() => flowResult(testState.queryState.updateLamba(stub_RawLambda())));
    return (_jsxs("div", { className: "panel mapping-test-editor__query-panel", children: [_jsxs("div", { className: "panel__header", children: [_jsx("div", { className: "panel__header__title", children: _jsx("div", { className: "panel__header__title__label", children: "query" }) }), _jsx("div", { className: "panel__header__actions", children: _jsxs("div", { className: "btn__dropdown-combo", children: [_jsxs("button", { className: "btn__dropdown-combo__label", onClick: editWithQueryBuilder(), title: "Edit Query", tabIndex: -1, children: [_jsx(PencilIcon, { className: "btn__dropdown-combo__label__icon" }), _jsx("div", { className: "btn__dropdown-combo__label__title", children: "Edit Query" })] }), _jsx(ControlledDropdownMenu, { className: "btn__dropdown-combo__dropdown-btn", content: _jsxs(MenuContent, { children: [_jsx(MenuContentItem, { className: "btn__dropdown-combo__option", onClick: editWithQueryBuilder(true), children: "Text Mode" }), _jsx(MenuContentItem, { className: "btn__dropdown-combo__option", onClick: clearQuery, children: "Clear Query" })] }), menuProps: {
                                        anchorOrigin: { vertical: 'bottom', horizontal: 'right' },
                                        transformOrigin: { vertical: 'top', horizontal: 'right' },
                                    }, children: _jsx(CaretDownIcon, {}) })] }) })] }), !isStubbed_RawLambda(queryState.query) && (_jsx(PanelContent, { children: _jsx("div", { className: "mapping-test-editor__query-panel__query", children: _jsx(CodeEditor, { inputValue: queryState.lambdaString, isReadOnly: true, language: CODE_EDITOR_LANGUAGE.PURE, hideMinimap: true }) }) })), isStubbed_RawLambda(queryState.query) && (_jsx(PanelContent, { children: _jsx(PanelDropZone, { dropTargetConnector: dropConnector, isDragOver: isDragOver, children: _jsx(BlankPanelPlaceholder, { text: "Choose a class mapping", onClick: showClassMappingSelectorModal, clickActionType: "add", tooltipText: "Drop a class mapping, or click to choose one to start building the query", isDropZoneActive: canDrop, disabled: isReadOnly }) }) })), openClassMappingSelectorModal && (_jsx(ClassMappingSelectorModal, { mappingEditorState: testState.mappingEditorState, hideClassMappingSelectorModal: hideClassMappingSelectorModal, changeClassMapping: changeClassMapping }))] }));
});
export const DEPRECATED__MappingTestObjectInputDataBuilder = observer((props) => {
    const { inputDataState, isReadOnly } = props;
    // TODO?: handle XML/type
    // Input data
    const updateInput = (val) => inputDataState.setData(val);
    return (_jsx("div", { className: "panel__content mapping-test-editor__input-data-panel__content", children: _jsx(CodeEditor, { language: CODE_EDITOR_LANGUAGE.JSON, inputValue: inputDataState.data, isReadOnly: isReadOnly, updateInput: updateInput }) }));
});
export const DEPRECATED__MappingTestFlatDataInputDataBuilder = observer((props) => {
    const { inputDataState, isReadOnly } = props;
    // Input data
    const updateInput = (val) => flatData_setData(inputDataState.inputData, val);
    return (_jsx("div", { className: "panel__content mapping-test-editor__input-data-panel__content", children: _jsx(CodeEditor, { language: CODE_EDITOR_LANGUAGE.TEXT, inputValue: inputDataState.inputData.data, isReadOnly: isReadOnly, updateInput: updateInput }) }));
});
/**
 * Right now, we always default this to use Local H2 connection.
 */
export const DEPRECATED__MappingTestRelationalInputDataBuilder = observer((props) => {
    const { inputDataState, isReadOnly } = props;
    // Input data
    const updateInput = (val) => relationalInputData_setData(inputDataState.inputData, val);
    return (_jsx("div", { className: "panel__content mapping-test-editor__input-data-panel__content", children: _jsx(CodeEditor, { language: getRelationalInputTestDataEditorLanguage(inputDataState.inputData.inputType), inputValue: inputDataState.inputData.data, isReadOnly: isReadOnly, updateInput: updateInput }) }));
});
const RelationalMappingTestInputDataTypeSelector = observer((props) => {
    const { inputDataState, isReadOnly } = props;
    const changeInputType = (val) => () => {
        relationalInputData_setInputType(inputDataState.inputData, val);
    };
    return (_jsx(ControlledDropdownMenu, { className: "mapping-test-editor__input-data-panel__type-selector", title: "Choose input data type...", disabled: isReadOnly, content: _jsx(MenuContent, { children: Object.keys(RelationalInputType).map((mode) => (_jsx(MenuContentItem, { className: "mapping-test-editor__input-data-panel__type-selector__option", onClick: changeInputType(mode), children: mode }, mode))) }), children: _jsxs("div", { className: "mapping-test-editor__input-data-panel__type-selector__value", children: [_jsx("div", { className: "mapping-test-editor__input-data-panel__type-selector__value__label", children: inputDataState.inputData.inputType }), _jsx(CaretDownIcon, {})] }) }));
});
export const DEPRECATED__MappingTestInputDataBuilder = observer((props) => {
    const { testState, isReadOnly } = props;
    const inputDataState = testState.inputDataState;
    const editorStore = useEditorStore();
    // Class mapping selector
    const [openClassMappingSelectorModal, setOpenClassMappingSelectorModal] = useState(false);
    const showClassMappingSelectorModal = () => setOpenClassMappingSelectorModal(true);
    const hideClassMappingSelectorModal = () => setOpenClassMappingSelectorModal(false);
    const changeClassMapping = useCallback((setImplementation) => {
        testState.setInputDataStateBasedOnSource(setImplementation
            ? getMappingElementSource(setImplementation, editorStore.pluginManager.getApplicationPlugins())
            : undefined, true);
        hideClassMappingSelectorModal();
    }, [testState, editorStore]);
    const classMappingFilterFn = (setImp) => !(setImp instanceof OperationSetImplementation);
    // input data builder
    let inputDataBuilder;
    if (inputDataState instanceof MappingTestObjectInputDataState) {
        inputDataBuilder = (_jsx(DEPRECATED__MappingTestObjectInputDataBuilder, { inputDataState: inputDataState, isReadOnly: isReadOnly }));
    }
    else if (inputDataState instanceof MappingTestFlatDataInputDataState) {
        inputDataBuilder = (_jsx(DEPRECATED__MappingTestFlatDataInputDataBuilder, { inputDataState: inputDataState, isReadOnly: isReadOnly }));
    }
    else if (inputDataState instanceof MappingTestRelationalInputDataState) {
        inputDataBuilder = (_jsx(DEPRECATED__MappingTestRelationalInputDataBuilder, { inputDataState: inputDataState, isReadOnly: isReadOnly }));
    }
    else {
        inputDataBuilder = null;
    }
    // input type
    let inputTypeSelector;
    if (inputDataState instanceof MappingTestRelationalInputDataState) {
        inputTypeSelector = (_jsx(RelationalMappingTestInputDataTypeSelector, { inputDataState: inputDataState, isReadOnly: isReadOnly }));
    }
    else {
        inputTypeSelector = null;
    }
    return (_jsxs("div", { className: "panel mapping-test-editor__input-data-panel", children: [_jsxs("div", { className: "panel__header", children: [_jsx("div", { className: "panel__header__title", children: _jsx("div", { className: "panel__header__title__label", children: "input data" }) }), _jsxs("div", { className: "panel__header__actions", children: [inputTypeSelector, _jsx("button", { className: "panel__header__action", tabIndex: -1, disabled: isReadOnly, onClick: showClassMappingSelectorModal, title: "Regenerate...", children: _jsx(RefreshIcon, { className: "mapping-test-editor__icon--refresh" }) })] })] }), inputDataBuilder, openClassMappingSelectorModal && (_jsx(ClassMappingSelectorModal, { mappingEditorState: testState.mappingEditorState, hideClassMappingSelectorModal: hideClassMappingSelectorModal, changeClassMapping: changeClassMapping, classMappingFilterFn: classMappingFilterFn }))] }));
});
export const DEPRECATED__MappingTestExpectedOutputAssertionBuilder = observer((props) => {
    const { testState, assertionState, isReadOnly } = props;
    const applicationStore = useApplicationStore();
    const validationResult = DEPRECATED__validate_MappingTestAssert(testState.test);
    const isValid = !validationResult;
    // Expected Result
    const updateExpectedResult = (val) => {
        assertionState.setExpectedResult(val);
        testState.updateAssertion();
    };
    const formatExpectedResultJSONString = () => assertionState.setExpectedResult(tryToFormatLosslessJSONString(assertionState.expectedResult));
    // Actions
    const regenerateExpectedResult = applicationStore.guardUnhandledError(() => flowResult(testState.regenerateExpectedResult()));
    return (_jsxs("div", { className: "panel mapping-test-editor__result-panel", children: [_jsxs("div", { className: "panel__header", children: [_jsx("div", { className: "panel__header__title", children: _jsx("div", { className: "panel__header__title__label", children: "expected" }) }), _jsxs("div", { className: "panel__header__actions", children: [_jsx("button", { className: "panel__header__action", disabled: testState.isExecutingTest || isReadOnly, onClick: regenerateExpectedResult, tabIndex: -1, title: "Regenerate Result", children: _jsx(RefreshIcon, { className: "mapping-test-editor__icon__regenerate-result" }) }), _jsx("button", { className: "panel__header__action", disabled: isReadOnly, tabIndex: -1, onClick: formatExpectedResultJSONString, title: "Format JSON", children: _jsx(WrenchIcon, {}) })] })] }), _jsxs("div", { className: clsx('panel__content mapping-test-editor__text-editor mapping-test-editor__result-panel__content', { 'panel__content--has-validation-error': !isValid }), children: [!isValid && (_jsx("div", { className: "panel__content__validation-error", title: validationResult.messages.join('\n'), children: _jsx(ErrorIcon, {}) })), _jsx(CodeEditor, { inputValue: assertionState.expectedResult, updateInput: updateExpectedResult, isReadOnly: isReadOnly, language: CODE_EDITOR_LANGUAGE.JSON })] })] }));
});
export const DEPRECATED__MappingTestAssertionBuilder = observer((props) => {
    const { testState, isReadOnly } = props;
    const assertionState = testState.assertionState;
    if (assertionState instanceof MappingTestExpectedOutputAssertionState) {
        return (_jsx(DEPRECATED__MappingTestExpectedOutputAssertionBuilder, { testState: testState, assertionState: assertionState, isReadOnly: isReadOnly }));
    }
    return null;
});
export const DEPRECATED__MappingTestBuilder = observer((props) => {
    const { testState, isReadOnly } = props;
    const applicationStore = useApplicationStore();
    // In case we switch out to another tab to do editing on some class, we want to refresh the test state data so that we can detect problem in deep fetch tree
    useEffect(() => {
        flowResult(testState.onTestStateOpen()).catch(applicationStore.alertUnhandledError);
    }, [applicationStore, testState]);
    return (_jsxs("div", { className: "mapping-test-editor", children: [_jsx(PanelLoadingIndicator, { isLoading: testState.isExecutingTest }), _jsxs(ResizablePanelGroup, { orientation: "horizontal", children: [_jsx(ResizablePanel, { size: 250, minSize: 28, children: _jsx(MappingTestQueryEditor, { testState: testState, isReadOnly: isReadOnly }, testState.queryState.uuid) }), _jsx(ResizablePanelSplitter, { children: _jsx(ResizablePanelSplitterLine, { color: "var(--color-dark-grey-50)" }) }), _jsx(ResizablePanel, { size: 250, minSize: 28, children: _jsx(DEPRECATED__MappingTestInputDataBuilder, { testState: testState, isReadOnly: isReadOnly }, testState.inputDataState.uuid) }), _jsx(ResizablePanelSplitter, { children: _jsx(ResizablePanelSplitterLine, { color: "var(--color-dark-grey-50)" }) }), _jsx(ResizablePanel, { minSize: 28, children: _jsx(DEPRECATED__MappingTestAssertionBuilder, { testState: testState, isReadOnly: isReadOnly }, testState.assertionState.uuid) })] })] }));
});
export const DEPRECATED__MappingTestEditor = observer((props) => {
    const { testState, isReadOnly } = props;
    const applicationStore = useApplicationStore();
    const selectedTab = testState.selectedTab;
    const changeTab = (tab) => () => testState.setSelectedTab(tab);
    // execute
    const runTest = applicationStore.guardUnhandledError(() => flowResult(testState.runTest()));
    const cancelTest = applicationStore.guardUnhandledError(() => flowResult(testState.cancelTest()));
    const executionPlanState = testState.executionPlanState;
    const generatePlan = applicationStore.guardUnhandledError(() => flowResult(testState.generatePlan(false)));
    const debugPlanGeneration = applicationStore.guardUnhandledError(() => flowResult(testState.generatePlan(true)));
    // Test Result
    let testResult = '';
    switch (testState.result) {
        case TEST_RESULT.NONE:
            testResult = 'Test did not run';
            break;
        case TEST_RESULT.FAILED:
            testResult = `Test failed in ${testState.runTime}ms, see comparison (expected <-> actual) below:`;
            break;
        case TEST_RESULT.PASSED:
            testResult = `Test passed in ${testState.runTime}ms`;
            break;
        case TEST_RESULT.ERROR:
            testResult = `Test failed in ${testState.runTime}ms due to error:\n${testState.errorRunningTest?.message ?? '(unknown)'}`;
            break;
        default:
            throw new IllegalStateError('Unknown test result state');
    }
    testResult = testState.isRunningTest ? 'Running test...' : testResult;
    return (_jsxs("div", { className: "mapping-test-editor", children: [_jsxs("div", { className: "mapping-test-editor__header", children: [_jsx("div", { className: "mapping-test-editor__header__tabs", children: Object.values(MAPPING_TEST_EDITOR_TAB_TYPE).map((tab) => (_jsxs("div", { onClick: changeTab(tab), className: clsx('mapping-test-editor__header__tab', {
                                'mapping-test-editor__header__tab--active': tab === selectedTab,
                            }), children: [tab === MAPPING_TEST_EDITOR_TAB_TYPE.RESULT && (_jsx("div", { className: "mapping-test-editor__header__tab__test-status-indicator__container", children: _jsx(MappingTestStatusIndicator, { testState: testState }) })), tab] }, tab))) }), _jsx("div", { className: "panel__header__actions mapping-test-editor__header__actions", children: _jsx("div", { className: "mapping-test-editor__action-btn btn__dropdown-combo btn__dropdown-combo--primary", children: testState.isRunningTest ? (_jsx("button", { className: "btn__dropdown-combo__canceler", onClick: cancelTest, tabIndex: -1, children: _jsxs("div", { className: "btn--dark btn--caution btn__dropdown-combo__canceler__label", children: [_jsx(PauseCircleIcon, { className: "btn__dropdown-combo__canceler__label__icon" }), _jsx("div", { className: "btn__dropdown-combo__canceler__label__title", children: "Stop" })] }) })) : (_jsxs(_Fragment, { children: [_jsxs("button", { className: "btn__dropdown-combo__label", onClick: runTest, disabled: testState.isExecutingTest || testState.isGeneratingPlan, tabIndex: -1, children: [_jsx(PlayIcon, { className: "btn__dropdown-combo__label__icon" }), _jsx("div", { className: "btn__dropdown-combo__label__title", children: "Run Test" })] }), _jsx(ControlledDropdownMenu, { className: "btn__dropdown-combo__dropdown-btn", disabled: testState.isExecutingTest || testState.isGeneratingPlan, content: _jsxs(MenuContent, { children: [_jsx(MenuContentItem, { className: "btn__dropdown-combo__option", onClick: generatePlan, children: "Generate Plan" }), _jsx(MenuContentItem, { className: "btn__dropdown-combo__option", onClick: debugPlanGeneration, children: "Debug" })] }), menuProps: {
                                            anchorOrigin: { vertical: 'bottom', horizontal: 'right' },
                                            transformOrigin: { vertical: 'top', horizontal: 'right' },
                                        }, children: _jsx(CaretDownIcon, {}) })] })) }) })] }), _jsxs("div", { className: "mapping-test-editor__content", children: [selectedTab === MAPPING_TEST_EDITOR_TAB_TYPE.SETUP && (_jsx(DEPRECATED__MappingTestBuilder, { testState: testState, isReadOnly: isReadOnly })), selectedTab === MAPPING_TEST_EDITOR_TAB_TYPE.RESULT && (_jsxs("div", { className: "mapping-test-editor__result", children: [_jsx("div", { className: `mapping-test-editor__result__status mapping-test-editor__result__status--${testState.isRunningTest
                                    ? 'running'
                                    : testState.result.toLowerCase()}`, children: testResult }), testState.result === TEST_RESULT.FAILED && (_jsx(_Fragment, { children: testState.assertionState instanceof
                                    MappingTestExpectedOutputAssertionState && (_jsx("div", { className: "mapping-test-editor__result__diff", children: _jsx(JSONDiffView, { from: testState.assertionState.expectedResult, to: testState.testExecutionResultText, lossless: true }) })) }))] }))] }), _jsx(ExecutionPlanViewer, { executionPlanState: executionPlanState })] }));
});
//# sourceMappingURL=DEPRECATED__MappingTestEditor.js.map