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 { useApplicationStore } from '@finos/legend-application';
import { BlankPanelPlaceholder, CaretDownIcon, clsx, ContextMenu, ControlledDropdownMenu, MenuContent, MenuContentItem, TimesIcon, PlusIcon, ExpandIcon, CompressIcon, CircleIcon, TrashIcon, NewFolderIcon, PlusCircleIcon, InfoCircleIcon, PanelDropZone, DragPreviewLayer, PanelEntryDropZonePlaceholder, useDragPreviewLayer, BlankPanelContent, PanelContent, MoreVerticalIcon, MenuContentItemIcon, MenuContentItemLabel, PanelLoadingIndicator, RefreshIcon, } from '@finos/legend-art';
import { Class, Enumeration, PrimitiveType, } from '@finos/legend-graph';
import { assertErrorThrown, guaranteeNonNullable, debounce, } from '@finos/legend-shared';
import { flowResult } from 'mobx';
import { observer } from 'mobx-react-lite';
import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState, } from 'react';
import { useDrop, useDrag, useDragLayer } from 'react-dnd';
import { PostFilterConditionState, QueryBuilderPostFilterTreeConditionNodeData, QueryBuilderPostFilterTreeGroupNodeData, QueryBuilderPostFilterTreeBlankConditionNodeData, QUERY_BUILDER_POST_FILTER_DND_TYPE, PostFilterValueSpecConditionValueState, PostFilterTDSColumnValueConditionValueState, } from '../../stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js';
import { QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE, QueryBuilderDerivationProjectionColumnState, } from '../../stores/fetch-structure/tds/projection/QueryBuilderProjectionColumnState.js';
import { QUERY_BUILDER_TEST_ID } from '../../__lib__/QueryBuilderTesting.js';
import { isTypeCompatibleForAssignment } from '../../stores/QueryBuilderValueSpecificationHelper.js';
import { QUERY_BUILDER_GROUP_OPERATION } from '../../stores/QueryBuilderGroupOperationHelper.js';
import { QueryBuilderTDSState } from '../../stores/fetch-structure/tds/QueryBuilderTDSState.js';
import { QUERY_BUILDER_VARIABLE_DND_TYPE, EditableBasicValueSpecificationEditor, } from '../shared/BasicValueSpecificationEditor.js';
import { QueryBuilderColumnInfoTooltip, renderPropertyTypeIcon, } from './QueryBuilderTDSComponentHelper.js';
import { QUERY_BUILDER_WINDOW_COLUMN_DND_TYPE, } from '../../stores/fetch-structure/tds/window/QueryBuilderWindowState.js';
import { QueryBuilderTelemetryHelper } from '../../__lib__/QueryBuilderTelemetryHelper.js';
import { QueryBuilderPanelIssueCountBadge } from '../shared/QueryBuilderPanelIssueCountBadge.js';
import { QueryBuilderPostFilterOperator_In, QueryBuilderPostFilterOperator_NotIn, } from '../../stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_In.js';
import { QueryBuilderPropertyNameDisplay } from '../QueryBuilderPropertyExpressionEditor.js';
import { convertTextToPrimitiveInstanceValue } from '../../stores/shared/ValueSpecificationEditorHelper.js';
import { getDNDItemType } from '../shared/QueryBuilderFilterHelper.js';
export const CAN_DROP_MAIN_GROUP_DND_TYPES = [
    QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE,
    QUERY_BUILDER_WINDOW_COLUMN_DND_TYPE,
];
export const CAN_DROP_POST_FILTER_NODE_DND_TYPES = [
    QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE,
    QUERY_BUILDER_WINDOW_COLUMN_DND_TYPE,
    QUERY_BUILDER_POST_FILTER_DND_TYPE.CONDITION,
];
export const CAN_DROP_POST_FILTER_VALUE_DND_TYPES = [
    QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE,
    QUERY_BUILDER_WINDOW_COLUMN_DND_TYPE,
    QUERY_BUILDER_VARIABLE_DND_TYPE,
];
const QueryBuilderPostFilterConditionContextMenu = observer(forwardRef(function QueryBuilderPostFilterConditionContextMenu(props, ref) {
    const { tdsState, node } = props;
    const postFilterState = tdsState.postFilterState;
    const removeNode = () => postFilterState.removeNodeAndPruneBranch(node);
    const createCondition = () => {
        postFilterState.addNodeFromNode(new QueryBuilderPostFilterTreeBlankConditionNodeData(undefined), node);
    };
    const createGroupCondition = () => {
        postFilterState.addGroupConditionNodeFromNode(node);
    };
    const newGroupWithCondition = () => {
        postFilterState.newGroupWithConditionFromNode(undefined, node);
    };
    return (_jsxs(MenuContent, { ref: ref, children: [node instanceof QueryBuilderPostFilterTreeGroupNodeData && (_jsx(MenuContentItem, { onClick: createCondition, children: "Add New Condition" })), node instanceof QueryBuilderPostFilterTreeGroupNodeData && (_jsx(MenuContentItem, { onClick: createGroupCondition, children: "Add New Logical Group" })), node instanceof QueryBuilderPostFilterTreeConditionNodeData && (_jsx(MenuContentItem, { onClick: newGroupWithCondition, children: "Form a New Logical Group" })), _jsx(MenuContentItem, { onClick: removeNode, children: "Remove" })] }));
}));
const QueryBuilderPostFilterGroupConditionEditor = observer((props) => {
    const { node, isDragOver, isDroppable } = props;
    const switchOperation = (event) => {
        event.stopPropagation(); // prevent triggering selecting the node
        node.setGroupOperation(node.groupOperation === QUERY_BUILDER_GROUP_OPERATION.AND
            ? QUERY_BUILDER_GROUP_OPERATION.OR
            : QUERY_BUILDER_GROUP_OPERATION.AND);
    };
    const operationName = node.groupOperation === QUERY_BUILDER_GROUP_OPERATION.AND ? 'AND' : 'OR';
    return (_jsx("div", { className: "dnd__entry__container", children: _jsx(PanelEntryDropZonePlaceholder, { isDragOver: isDragOver, isDroppable: isDroppable, label: operationName, className: "query-builder-post-filter-tree__group-node__drop-zone", children: _jsx("div", { className: "query-builder-post-filter-tree__group-node", title: "Switch Operation", onClick: switchOperation, children: _jsx("div", { className: "query-builder-post-filter-tree__group-node__label editable-value", children: node.groupOperation }) }) }) }));
});
export const QueryBuilderColumnBadge = observer((props) => {
    const { colState, removeColumn } = props;
    const type = colState.getColumnType();
    return (_jsx("div", { className: "query-builder-column-badge", children: _jsxs("div", { className: "query-builder-column-badge__content", children: [type && (_jsx("div", { className: clsx('query-builder-column-badge__type', {
                        'query-builder-column-badge__type--class': type instanceof Class,
                        'query-builder-column-badge__type--enumeration': type instanceof Enumeration,
                        'query-builder-column-badge__type--primitive': type instanceof PrimitiveType,
                    }), children: renderPropertyTypeIcon(type) })), _jsx("div", { className: "query-builder-column-badge__property", title: `${colState.columnName}`, children: colState.columnName }), _jsx(QueryBuilderColumnInfoTooltip, { columnState: colState, placement: "bottom-end", children: _jsx("div", { className: "query-builder-column-badge__property__info", children: _jsx(InfoCircleIcon, {}) }) }), _jsx("button", { className: "query-builder-column-badge__action", name: "Reset", title: "Reset", onClick: removeColumn, children: _jsx(RefreshIcon, {}) })] }) }));
});
const canDropTypeOntoNodeValue = (type, condition) => {
    const conditionOperator = condition.operator;
    const conditionValueType = condition.leftConditionValue.getColumnType();
    return (conditionValueType !== undefined &&
        !(conditionOperator instanceof QueryBuilderPostFilterOperator_In) &&
        !(conditionOperator instanceof QueryBuilderPostFilterOperator_NotIn) &&
        isTypeCompatibleForAssignment(type, conditionValueType));
};
const QueryBuilderPostFilterConditionEditor = observer((props) => {
    const { node, isDragOver } = props;
    const queryBuilderState = node.condition.postFilterState.tdsState.queryBuilderState;
    const graph = queryBuilderState.graphManagerState.graph;
    const applicationStore = useApplicationStore();
    const changeOperator = (val) => () => node.condition.changeOperator(val);
    const rightConditionValue = node.condition.rightConditionValue;
    // Drag and Drop on filter condition value
    const handleDrop = useCallback((item, type) => {
        const itemType = getDNDItemType(item, type);
        const conditionValueType = node.condition.leftConditionValue.getColumnType();
        if (canDropTypeOntoNodeValue(itemType, node.condition)) {
            if (type === QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE ||
                type === QUERY_BUILDER_WINDOW_COLUMN_DND_TYPE) {
                const columnState = item
                    .columnState;
                node.condition.setRightConditionVal(new PostFilterTDSColumnValueConditionValueState(node.condition, columnState));
            }
            else if (type === QUERY_BUILDER_VARIABLE_DND_TYPE) {
                const variable = item.variable;
                node.condition.buildFromValueSpec(variable);
            }
            else {
                applicationStore.notificationService.notifyWarning(`Dragging and Dropping ${type} to post-filter panel is not supported.`);
            }
        }
        else {
            applicationStore.notificationService.notifyWarning(`Incompatible parameter type ${itemType?.name}. ${itemType?.name} is not compatible with type ${conditionValueType?.name}.`);
        }
    }, [applicationStore, node.condition]);
    const [{ isFilterValueDragOver }, dropConnector] = useDrop(() => ({
        accept: CAN_DROP_POST_FILTER_VALUE_DND_TYPES,
        canDrop: (item, monitor) => canDropTypeOntoNodeValue(getDNDItemType(item, monitor.getItemType()), node.condition),
        drop: (item, monitor) => {
            if (!monitor.didDrop()) {
                handleDrop(item, monitor.getItemType());
            } // prevent drop event propagation to accomondate for nested DnD
        },
        collect: (monitor) => ({
            isFilterValueDragOver: monitor.isOver({ shallow: true }) && monitor.canDrop(),
        }),
    }), [handleDrop]);
    const ref = useRef(null);
    dropConnector(ref);
    const { isFilterValueDroppable } = useDragLayer((monitor) => ({
        isFilterValueDroppable: monitor.isDragging() &&
            CAN_DROP_POST_FILTER_VALUE_DND_TYPES.includes(monitor.getItemType()?.toString() ?? '') &&
            canDropTypeOntoNodeValue(getDNDItemType(monitor.getItem(), monitor.getItemType()), node.condition),
    }));
    const resetNode = () => {
        node.condition.buildFromValueSpec(node.condition.operator.getDefaultFilterConditionValue(node.condition));
    };
    const debouncedTypeaheadSearch = useMemo(() => debounce((inputValue) => {
        const inputValueSpec = convertTextToPrimitiveInstanceValue(PrimitiveType.STRING, inputValue, queryBuilderState.observerContext);
        return node.condition.handleTypeaheadSearch(inputValueSpec ?? undefined);
    }, 1000), [node, queryBuilderState.observerContext]);
    const cleanUpReloadValues = () => {
        node.condition.typeaheadSearchState.complete();
    };
    const changeValueSpecification = (val) => {
        node.condition.buildFromValueSpec(val);
    };
    const selectorConfig = {
        values: node.condition.typeaheadSearchResults,
        isLoading: node.condition.typeaheadSearchState.isInProgress,
        reloadValues: debouncedTypeaheadSearch,
        cleanUpReloadValues,
    };
    const removeTDSColumnValue = () => {
        node.condition.buildFromValueSpec(node.condition.operator.getDefaultFilterConditionValue(node.condition));
    };
    const renderRightVal = () => {
        if (rightConditionValue instanceof PostFilterValueSpecConditionValueState &&
            rightConditionValue.value) {
            return (_jsx("div", { ref: ref, className: "query-builder-post-filter-tree__condition-node__value", children: _jsx(PanelEntryDropZonePlaceholder, { isDragOver: isFilterValueDragOver, isDroppable: isFilterValueDroppable, label: "Change Filter Value", children: _jsx(EditableBasicValueSpecificationEditor, { valueSpecification: rightConditionValue.value, setValueSpecification: changeValueSpecification, graph: graph, observerContext: queryBuilderState.observerContext, typeCheckOption: {
                            expectedType: guaranteeNonNullable(node.condition.leftConditionValue.getColumnType()),
                        }, resetValue: resetNode, selectorSearchConfig: selectorConfig, isConstant: queryBuilderState.constantState.isValueSpecConstant(rightConditionValue.value), initializeAsEditable: node.isNewlyAdded }) }) }));
        }
        else if (rightConditionValue instanceof
            PostFilterTDSColumnValueConditionValueState) {
            return (_jsx("div", { ref: ref, className: "query-builder-post-filter-tree__condition-node__value", children: _jsx(PanelEntryDropZonePlaceholder, { isDragOver: isFilterValueDragOver, isDroppable: isFilterValueDroppable, label: "Change Filter Value", children: _jsx(QueryBuilderColumnBadge, { colState: rightConditionValue.tdsColumn, removeColumn: removeTDSColumnValue }) }) }));
        }
        return null;
    };
    useEffect(() => {
        node.setIsNewlyAdded(false);
    }, [node]);
    return (_jsx("div", { className: "dnd__entry__container", children: _jsx(PanelEntryDropZonePlaceholder, { isDragOver: isDragOver && !isFilterValueDragOver, alwaysShowChildren: true, children: _jsxs("div", { className: "query-builder-post-filter-tree__condition-node", children: [_jsx("div", { className: "query-builder-post-filter-tree__condition-node__property", children: _jsx(QueryBuilderPropertyNameDisplay, { columnName: node.condition.leftConditionValue.columnName, title: node.condition.leftConditionValue.columnName }) }), _jsxs(ControlledDropdownMenu, { className: "query-builder-post-filter-tree__condition-node__operator", title: "Choose Operator...", content: _jsx(MenuContent, { children: node.condition.operators.map((op) => (_jsx(MenuContentItem, { className: "query-builder-post-filter-tree__condition-node__operator__dropdown__option", onClick: changeOperator(op), children: op.getLabel() }, op.uuid))) }), menuProps: {
                            anchorOrigin: { vertical: 'bottom', horizontal: 'left' },
                            transformOrigin: { vertical: 'top', horizontal: 'left' },
                            elevation: 7,
                        }, children: [_jsx("div", { className: "query-builder-post-filter-tree__condition-node__operator__label", children: node.condition.operator.getLabel() }), _jsx("div", { className: "query-builder-post-filter-tree__condition-node__operator__dropdown__trigger", children: _jsx(CaretDownIcon, {}) })] }), renderRightVal()] }) }) }));
});
const QueryBuilderPostFilterBlankConditionEditor = observer((props) => {
    const { isDragOver, isDroppable } = props;
    return (_jsx("div", { className: "query-builder-post-filter-tree__node__label__content", children: _jsx(PanelEntryDropZonePlaceholder, { isDragOver: isDragOver, isDroppable: isDroppable, label: "Create Condition", children: _jsx("div", { className: "query-builder-post-filter-tree__blank-node", children: "blank" }) }) }));
});
const QueryBuilderPostFilterTreeNodeContainer = observer((props) => {
    const { node, onNodeSelect, innerProps } = props;
    const { tdsState } = innerProps;
    const ref = useRef(null);
    const [isSelectedFromContextMenu, setIsSelectedFromContextMenu] = useState(false);
    const applicationStore = useApplicationStore();
    const postFilterState = tdsState.postFilterState;
    const selectNode = () => onNodeSelect?.(node);
    const removeNode = () => postFilterState.removeNodeAndPruneBranch(node);
    // Drag and Drop
    const handleDrop = useCallback((item, type) => {
        if (QUERY_BUILDER_POST_FILTER_DND_TYPE.CONDITION === type) {
            const nodeBeingDragged = item.node;
            const newCreatedNode = new QueryBuilderPostFilterTreeConditionNodeData(undefined, postFilterState.nodes.get(nodeBeingDragged.id).condition, true);
            if (node instanceof QueryBuilderPostFilterTreeConditionNodeData) {
                postFilterState.newGroupWithConditionFromNode(newCreatedNode, node);
                postFilterState.removeNodeAndPruneBranch(nodeBeingDragged);
            }
            else if (node instanceof QueryBuilderPostFilterTreeGroupNodeData) {
                postFilterState.addNodeFromNode(newCreatedNode, node);
                postFilterState.removeNodeAndPruneBranch(nodeBeingDragged);
            }
            else if (node instanceof QueryBuilderPostFilterTreeBlankConditionNodeData) {
                postFilterState.replaceBlankNodeWithNode(newCreatedNode, node);
                postFilterState.removeNodeAndPruneBranch(nodeBeingDragged);
            }
        }
        else if (type === QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE ||
            type === QUERY_BUILDER_WINDOW_COLUMN_DND_TYPE) {
            const columnState = item.columnState;
            let conditionState;
            try {
                conditionState = new PostFilterConditionState(postFilterState, columnState, undefined);
                conditionState.buildFromValueSpec(conditionState.operator.getDefaultFilterConditionValue(conditionState));
            }
            catch (error) {
                assertErrorThrown(error);
                applicationStore.notificationService.notifyWarning(error.message);
                return;
            }
            if (node instanceof QueryBuilderPostFilterTreeGroupNodeData) {
                postFilterState.addNodeFromNode(new QueryBuilderPostFilterTreeConditionNodeData(undefined, conditionState, true), node);
            }
            else if (node instanceof QueryBuilderPostFilterTreeConditionNodeData) {
                postFilterState.newGroupWithConditionFromNode(new QueryBuilderPostFilterTreeConditionNodeData(undefined, conditionState), node);
            }
            else if (node instanceof QueryBuilderPostFilterTreeBlankConditionNodeData) {
                postFilterState.replaceBlankNodeWithNode(new QueryBuilderPostFilterTreeConditionNodeData(undefined, conditionState), node);
            }
        }
    }, [applicationStore, postFilterState, node]);
    const [{ isDragOver, deepIsDragOver }, dropConnector] = useDrop(() => ({
        accept: CAN_DROP_POST_FILTER_NODE_DND_TYPES,
        drop: (item, monitor) => {
            if (!monitor.didDrop()) {
                handleDrop(item, monitor.getItemType());
            } // prevent drop event propagation to accomondate for nested DnD
        },
        collect: (monitor) => ({
            isDragOver: monitor.isOver({ shallow: true }),
            deepIsDragOver: monitor.isOver({ shallow: false }),
        }),
    }), [handleDrop]);
    const [, dragConnector, dragPreviewConnector] = useDrag(() => ({
        type: node instanceof QueryBuilderPostFilterTreeGroupNodeData
            ? QUERY_BUILDER_POST_FILTER_DND_TYPE.GROUP_CONDITION
            : node instanceof QueryBuilderPostFilterTreeConditionNodeData
                ? QUERY_BUILDER_POST_FILTER_DND_TYPE.CONDITION
                : QUERY_BUILDER_POST_FILTER_DND_TYPE.BLANK_CONDITION,
        item: () => ({ node }),
        end: () => postFilterState.setRearrangingConditions(false),
        canDrag: () => node instanceof QueryBuilderPostFilterTreeConditionNodeData ||
            node instanceof QueryBuilderPostFilterTreeBlankConditionNodeData,
    }), [node, postFilterState]);
    dragConnector(dropConnector(ref));
    useDragPreviewLayer(dragPreviewConnector);
    const { isDroppable } = useDragLayer((monitor) => ({
        isDroppable: monitor.isDragging() &&
            CAN_DROP_POST_FILTER_NODE_DND_TYPES.includes(monitor.getItemType()?.toString() ?? ''),
    }));
    // context menu
    const onContextMenuOpen = () => setIsSelectedFromContextMenu(true);
    const onContextMenuClose = () => setIsSelectedFromContextMenu(false);
    const showRemoveButton = node instanceof QueryBuilderPostFilterTreeConditionNodeData ||
        node instanceof QueryBuilderPostFilterTreeBlankConditionNodeData;
    return (_jsx("div", { "data-testid": QUERY_BUILDER_TEST_ID.QUERY_BUILDER_POST_FILTER_TREE_NODE_CONTAINER, className: clsx('query-builder-post-filter-tree__node__container', {
            'query-builder-post-filter-tree__node__container--group': node instanceof QueryBuilderPostFilterTreeGroupNodeData,
            'query-builder-post-filter-tree__node__container--condition': node instanceof QueryBuilderPostFilterTreeConditionNodeData ||
                node instanceof QueryBuilderPostFilterTreeBlankConditionNodeData,
            'query-builder-post-filter-tree__node__container--no-hover': postFilterState.isRearrangingConditions,
            'query-builder-post-filter-tree__node__container--selected': node === postFilterState.selectedNode,
            'query-builder-post-filter-tree__node__container--selected-from-context-menu': isSelectedFromContextMenu,
        }), children: _jsxs(ContextMenu, { content: _jsx(QueryBuilderPostFilterConditionContextMenu, { tdsState: tdsState, node: node }), menuProps: { elevation: 7 }, onOpen: onContextMenuOpen, onClose: onContextMenuClose, className: "query-builder-post-filter-tree__node__context-menu", children: [_jsxs("div", { "data-testid": QUERY_BUILDER_TEST_ID.QUERY_BUILDER_POST_FILTER_TREE_NODE_CONTENT, className: "query-builder-post-filter-tree__node__content", ref: ref, onClick: node instanceof QueryBuilderPostFilterTreeConditionNodeData ||
                        node instanceof QueryBuilderPostFilterTreeBlankConditionNodeData
                        ? selectNode
                        : undefined, children: [node instanceof QueryBuilderPostFilterTreeGroupNodeData && (_jsx(QueryBuilderPostFilterGroupConditionEditor, { node: node, isDroppable: isDroppable, isDragOver: isDragOver })), node instanceof QueryBuilderPostFilterTreeConditionNodeData && (_jsx(QueryBuilderPostFilterConditionEditor, { node: node, isDragOver: deepIsDragOver })), node instanceof
                            QueryBuilderPostFilterTreeBlankConditionNodeData && (_jsx(QueryBuilderPostFilterBlankConditionEditor, { node: node, isDragOver: isDragOver, isDroppable: isDroppable }))] }), showRemoveButton && (_jsx("div", { className: "query-builder-post-filter-tree__node__actions", children: _jsx("button", { className: "query-builder-post-filter-tree__node__action", tabIndex: -1, title: "Remove", onClick: removeNode, children: _jsx(TimesIcon, {}) }) }))] }) }));
});
const QueryBuilderPostFilterTreeNodeView = observer((props) => {
    const { node, level, onNodeSelect, getChildNodes, stepPaddingInRem, innerProps, } = props;
    return (_jsxs("div", { "data-testid": QUERY_BUILDER_TEST_ID.QUERY_BUILDER_POST_FILTER_TREE_NODE_BLOCK, className: clsx('query-builder-post-filter-tree__node__block', {
            'query-builder-post-filter-tree__node__block--group': node instanceof QueryBuilderPostFilterTreeGroupNodeData,
        }), children: [_jsx(QueryBuilderPostFilterTreeNodeContainer, { node: node, level: level + 1, stepPaddingInRem: stepPaddingInRem, onNodeSelect: onNodeSelect, innerProps: innerProps }), node.isOpen && getChildNodes(node).length > 0 && (_jsx("div", { "data-testid": QUERY_BUILDER_TEST_ID.QUERY_BUILDER_POST_FILTER_TREE_NODE_CHILDREN, className: "query-builder-post-filter-tree__node__children", children: getChildNodes(node).map((childNode) => (_jsx(QueryBuilderPostFilterTreeNodeView, { node: childNode, level: level + 1, onNodeSelect: onNodeSelect, getChildNodes: getChildNodes, innerProps: innerProps }, childNode.id))) }))] }));
});
const QueryBuilderPostFilterTree = observer((props) => {
    const { tdsState } = props;
    const postFilterState = tdsState.postFilterState;
    const rootNodes = postFilterState.rootIds.map((rootId) => postFilterState.getNode(rootId));
    const onNodeSelect = (node) => postFilterState.setSelectedNode(postFilterState.selectedNode !== node ? node : undefined);
    const getChildNodes = (node) => node instanceof QueryBuilderPostFilterTreeGroupNodeData
        ? node.childrenIds.map((id) => postFilterState.getNode(id))
        : [];
    return (_jsx("div", { "data-testid": QUERY_BUILDER_TEST_ID.QUERY_BUILDER_POST_FILTER_TREE, className: "tree-view__node__root query-builder-post-filter-tree__root", children: rootNodes.map((node) => (_jsx(QueryBuilderPostFilterTreeNodeView, { level: 0, node: node, getChildNodes: getChildNodes, onNodeSelect: onNodeSelect, innerProps: {
                tdsState: tdsState,
            } }, node.id))) }));
});
const QueryBuilderPostFilterPanelContent = observer((props) => {
    const { tdsState } = props;
    const applicationStore = useApplicationStore();
    const postFilterState = tdsState.postFilterState;
    const rootNode = postFilterState.getRootNode();
    // actions
    const collapseTree = () => {
        QueryBuilderTelemetryHelper.logEvent_PostFilterCollapseTreeLaunched(applicationStore.telemetryService);
        postFilterState.setSelectedNode(undefined);
        postFilterState.collapseTree();
    };
    const expandTree = () => {
        QueryBuilderTelemetryHelper.logEvent_PostFilterExpandTreeLaunched(applicationStore.telemetryService);
        postFilterState.setSelectedNode(undefined);
        postFilterState.expandTree();
    };
    const pruneTree = () => {
        QueryBuilderTelemetryHelper.logEvent_PostFilterCleanupTreeLaunched(applicationStore.telemetryService);
        postFilterState.pruneTree();
    };
    const simplifyTree = () => {
        QueryBuilderTelemetryHelper.logEvent_PostFilterSimplifyTreeLaunched(applicationStore.telemetryService);
        postFilterState.simplifyTree();
    };
    const createCondition = () => {
        QueryBuilderTelemetryHelper.logEvent_PostFilterCreateConditionLaunched(applicationStore.telemetryService);
        postFilterState.addNodeFromNode(new QueryBuilderPostFilterTreeBlankConditionNodeData(undefined), postFilterState.selectedNode);
    };
    const allowGroupCreation = postFilterState.isEmpty || // either the tree is empty
        (postFilterState.selectedNode && // or a node is currently selected which is...
            (postFilterState.selectedNode !== rootNode || // either not a root node
                rootNode instanceof QueryBuilderPostFilterTreeGroupNodeData)); // or if it is the root note, it has to be a group node
    const createGroupCondition = () => {
        QueryBuilderTelemetryHelper.logEvent_PostFilterCreateLogicalGroupLaunched(applicationStore.telemetryService);
        if (allowGroupCreation) {
            postFilterState.addGroupConditionNodeFromNode(postFilterState.selectedNode);
        }
    };
    const newGroupWithCondition = () => {
        QueryBuilderTelemetryHelper.logEvent_PostFilterCreateGroupFromConditionLaunched(applicationStore.telemetryService);
        if (postFilterState.selectedNode instanceof
            QueryBuilderPostFilterTreeConditionNodeData) {
            postFilterState.newGroupWithConditionFromNode(undefined, postFilterState.selectedNode);
        }
    };
    const { isDroppable } = useDragLayer((monitor) => ({
        isDroppable: monitor.isDragging() &&
            CAN_DROP_MAIN_GROUP_DND_TYPES.includes(monitor.getItemType()?.toString() ?? ''),
    }));
    // Drag and Drop
    const handleDrop = useCallback(async (item) => {
        let postFilterConditionState;
        try {
            const columnState = item
                .columnState;
            const aggregateColumnState = tdsState.aggregationState.columns.find((column) => column.projectionColumnState === columnState);
            if (!aggregateColumnState &&
                columnState instanceof QueryBuilderDerivationProjectionColumnState) {
                await flowResult(columnState.fetchDerivationLambdaReturnType({
                    isBeingDropped: true,
                }));
            }
            postFilterConditionState = new PostFilterConditionState(postFilterState, aggregateColumnState ?? columnState, undefined);
            postFilterConditionState.buildFromValueSpec(postFilterConditionState.operator.getDefaultFilterConditionValue(postFilterConditionState));
        }
        catch (error) {
            assertErrorThrown(error);
            applicationStore.notificationService.notifyError(error.message);
            return;
        }
        // NOTE: unfocus the current node when DnD a new node to the tree
        postFilterState.setSelectedNode(undefined);
        postFilterState.addNodeFromNode(new QueryBuilderPostFilterTreeConditionNodeData(undefined, postFilterConditionState, true), undefined);
    }, [applicationStore, postFilterState, tdsState.aggregationState.columns]);
    const [{ isDragOver }, dropConnector] = useDrop(() => ({
        accept: CAN_DROP_MAIN_GROUP_DND_TYPES,
        drop: (item, monitor) => {
            if (!monitor.didDrop()) {
                handleDrop(item).catch(applicationStore.alertUnhandledError);
            }
        },
        collect: (monitor) => ({
            isDragOver: monitor.isOver({ shallow: true }),
        }),
    }), [applicationStore, handleDrop]);
    const ref = useRef(null);
    dropConnector(ref);
    return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "panel__header", children: [_jsxs("div", { className: "panel__header__title", children: [_jsx("div", { className: "panel__header__title__label", children: "post-filter" }), postFilterState.allValidationIssues.length !== 0 && (_jsx(QueryBuilderPanelIssueCountBadge, { issues: postFilterState.allValidationIssues }))] }), _jsx("div", { className: "panel__header__actions", children: _jsx(ControlledDropdownMenu, { className: "panel__header__action", title: "Show Post-Filter Options Menu...", content: _jsxs(MenuContent, { children: [_jsxs(MenuContentItem, { onClick: createCondition, children: [_jsx(MenuContentItemIcon, { children: _jsx(PlusIcon, {}) }), _jsx(MenuContentItemLabel, { children: "Create Condition" })] }), _jsxs(MenuContentItem, { disabled: !(postFilterState.selectedNode instanceof
                                            QueryBuilderPostFilterTreeConditionNodeData), onClick: newGroupWithCondition, children: [_jsx(MenuContentItemIcon, { children: _jsx(PlusCircleIcon, {}) }), _jsx(MenuContentItemLabel, { children: "Create Group From Condition" })] }), _jsxs(MenuContentItem, { disabled: !allowGroupCreation, title: !allowGroupCreation
                                            ? 'Please select a filter node first to create logical group'
                                            : '', onClick: createGroupCondition, children: [_jsx(MenuContentItemIcon, { children: _jsx(NewFolderIcon, {}) }), _jsx(MenuContentItemLabel, { children: "Create Logical Group" })] }), _jsxs(MenuContentItem, { onClick: pruneTree, children: [_jsx(MenuContentItemIcon, { children: _jsx(TrashIcon, {}) }), _jsx(MenuContentItemLabel, { children: "Cleanup Tree" })] }), _jsxs(MenuContentItem, { onClick: simplifyTree, children: [_jsx(MenuContentItemIcon, { children: _jsx(CircleIcon, {}) }), _jsx(MenuContentItemLabel, { children: "Simplify Tree" })] }), _jsxs(MenuContentItem, { onClick: collapseTree, children: [_jsx(MenuContentItemIcon, { children: _jsx(CompressIcon, {}) }), _jsx(MenuContentItemLabel, { children: "Collapse Tree" })] }), _jsxs(MenuContentItem, { onClick: expandTree, children: [_jsx(MenuContentItemIcon, { children: _jsx(ExpandIcon, {}) }), _jsx(MenuContentItemLabel, { children: "Expand Tree" })] })] }), children: _jsx(MoreVerticalIcon, { className: "query-builder__icon__more-options" }) }) })] }), _jsx(PanelContent, { children: _jsxs(PanelDropZone, { isDragOver: isDragOver && postFilterState.isEmpty, isDroppable: isDroppable && postFilterState.isEmpty, dropTargetConnector: dropConnector, children: [_jsx(PanelLoadingIndicator, { isLoading: Boolean(postFilterState.derivedColumnBeingDropped) }), postFilterState.isEmpty && (_jsx(BlankPanelPlaceholder, { text: "Add a post-filter condition", tooltipText: "Drag and drop properties here" })), !postFilterState.isEmpty && (_jsxs(_Fragment, { children: [_jsx(DragPreviewLayer, { labelGetter: (item) => item.node.dragPreviewLabel, types: Object.values(QUERY_BUILDER_POST_FILTER_DND_TYPE) }), _jsx(QueryBuilderPostFilterTree, { tdsState: tdsState })] })), isDroppable && !postFilterState.isEmpty && (_jsx("div", { ref: ref, className: "query-builder-post-filter-tree__free-drop-zone__container", children: _jsx(PanelEntryDropZonePlaceholder, { isDragOver: isDragOver, isDroppable: isDroppable, className: "query-builder-post-filter-tree__free-drop-zone", label: "Add post-filter to main group", children: _jsx(_Fragment, {}) }) }))] }) })] }));
});
export const QueryBuilderPostFilterPanel = observer((props) => {
    const { queryBuilderState } = props;
    const fetchStructureImplementation = queryBuilderState.fetchStructureState.implementation;
    return (_jsxs("div", { "data-testid": QUERY_BUILDER_TEST_ID.QUERY_BUILDER_POST_FILTER_PANEL, className: "panel", children: [fetchStructureImplementation instanceof QueryBuilderTDSState && (_jsx(QueryBuilderPostFilterPanelContent, { tdsState: fetchStructureImplementation })), !(fetchStructureImplementation instanceof QueryBuilderTDSState) && (_jsxs(_Fragment, { children: [_jsx("div", { className: "panel__header", children: _jsx("div", { className: "panel__header__title", children: _jsx("div", { className: "panel__header__title__label", children: "post-filter" }) }) }), _jsx(PanelContent, { children: _jsx(BlankPanelContent, { children: "Post-filter is not supported for the current fetch-structure" }) })] }))] }));
});
//# sourceMappingURL=QueryBuilderPostFilterPanel.js.map