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 { forwardRef, useMemo, useRef, useState } from 'react';
import { observer } from 'mobx-react-lite';
import { clsx, TreeView, BlankPanelContent, ContextMenu, MenuContent, MenuContentItem, DragPreviewLayer, useDragPreviewLayer, PanelHeader, ChevronDownIcon, ChevronRightIcon, InfoCircleIcon, Tooltip, PURE_DataProductIcon, PURE_IngestIcon, PURE_DatabaseIcon, PURE_UnknownElementTypeIcon, } from '@finos/legend-art';
import { useDrag } from 'react-dnd';
import { DataProductAccessor, IngestionAccessor, InstanceValue, RelationalStoreAccessor, getMultiplicityDescription, } from '@finos/legend-graph';
import { QUERY_BUILDER_EXPLORER_TREE_DND_TYPE, QueryBuilderExplorerTreeRelationColumnNodeData, QueryBuilderExplorerTreeRelationRootNodeData, } from '../../stores/explorer/QueryBuilderExplorerState.js';
import { isExplorerTreeNodeAlreadyUsed, renderPropertyTypeIcon, } from './QueryBuilderExplorerPanel.js';
import { QUERY_BUILDER_TEST_ID } from '../../__lib__/QueryBuilderTesting.js';
import { isNonNullable, prettyCONSTName } from '@finos/legend-shared';
import { QueryBuilderBaseInfoTooltip } from '../shared/QueryBuilderPropertyInfoTooltip.js';
import { QueryBuilderTDSState } from '../../stores/fetch-structure/tds/QueryBuilderTDSState.js';
import { QueryBuilderRelationColumnProjectionColumnState } from '../../stores/fetch-structure/tds/projection/QueryBuilderProjectionColumnState.js';
const RELATION_ROOT_NODE_ID = '__relation_root__';
const getAccessorIcon = (accessor) => {
    if (accessor instanceof DataProductAccessor) {
        return _jsx(PURE_DataProductIcon, {});
    }
    else if (accessor instanceof IngestionAccessor) {
        return _jsx(PURE_IngestIcon, {});
    }
    else if (accessor instanceof RelationalStoreAccessor) {
        return _jsx(PURE_DatabaseIcon, {});
    }
    return _jsx(PURE_UnknownElementTypeIcon, {});
};
const getAccessorPath = (accessor) => [accessor.accessorOwner, accessor.schema, accessor.accessor]
    .filter(isNonNullable)
    .join('.');
const getColumnTypeLabel = (column) => {
    const typeName = column.genericType.value.rawType.name;
    const typeVariableValues = column.genericType.value.typeVariableValues;
    if (typeVariableValues && typeVariableValues.length > 0) {
        const args = typeVariableValues
            .map((v) => (v instanceof InstanceValue ? v.values[0] : undefined))
            .filter(isNonNullable);
        if (args.length > 0) {
            return `${typeName}(${args.join(', ')})`;
        }
    }
    return typeName;
};
const buildRelationTreeData = (accessor) => {
    const rootIds = [];
    const nodes = new Map();
    const columnIds = [];
    accessor.relationType.columns.forEach((column) => {
        const type = column.genericType.value.rawType;
        const node = new QueryBuilderExplorerTreeRelationColumnNodeData(column.name, column.name, column.name, column, type, { mapped: true });
        columnIds.push(node.id);
        nodes.set(node.id, node);
    });
    const rootNode = new QueryBuilderExplorerTreeRelationRootNodeData(RELATION_ROOT_NODE_ID, accessor.accessor, accessor.accessor, false, accessor.relationType, { mapped: true }, columnIds);
    rootNode.setIsOpen(true);
    rootIds.push(rootNode.id);
    nodes.set(rootNode.id, rootNode);
    return { rootIds, nodes };
};
const QueryBuilderRelationExplorerContextMenu = observer(forwardRef(function QueryBuilderRelationExplorerContextMenu(props, ref) {
    const { queryBuilderState, node, accessor } = props;
    const tdsState = queryBuilderState.fetchStructureState.implementation instanceof
        QueryBuilderTDSState
        ? queryBuilderState.fetchStructureState.implementation
        : undefined;
    const addColumnToFetchStructure = () => {
        if (tdsState &&
            node instanceof QueryBuilderExplorerTreeRelationColumnNodeData) {
            tdsState.addColumn(new QueryBuilderRelationColumnProjectionColumnState(tdsState, node.column, true));
        }
    };
    const addAllColumnsToFetchStructure = () => {
        if (tdsState) {
            accessor.relationType.columns.forEach((column) => {
                tdsState.addColumn(new QueryBuilderRelationColumnProjectionColumnState(tdsState, column, true));
            });
        }
    };
    return (_jsxs(MenuContent, { ref: ref, children: [node instanceof QueryBuilderExplorerTreeRelationColumnNodeData && (_jsx(MenuContentItem, { onClick: addColumnToFetchStructure, children: "Add Column to Fetch Structure" })), node instanceof QueryBuilderExplorerTreeRelationRootNodeData && (_jsx(MenuContentItem, { onClick: addAllColumnsToFetchStructure, children: "Add Columns to Fetch Structure" }))] }));
}));
const QueryBuilderRelationNodeContainer = observer((props) => {
    const { node, level, stepPaddingInRem, onNodeSelect, innerProps } = props;
    const { queryBuilderState, accessor } = innerProps;
    const isRoot = node instanceof QueryBuilderExplorerTreeRelationRootNodeData;
    const isColumn = node instanceof QueryBuilderExplorerTreeRelationColumnNodeData;
    const [isSelectedFromContextMenu, setIsSelectedFromContextMenu] = useState(false);
    const [, dragConnector, dragPreviewConnector] = useDrag(() => ({
        type: QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.RELATION_COLUMN,
        item: () => ({
            node: node,
        }),
    }), [node]);
    const ref = useRef(null);
    if (isColumn) {
        dragConnector(ref);
    }
    useDragPreviewLayer(dragPreviewConnector);
    const explorerState = queryBuilderState.explorerState;
    const columnLabel = isColumn && explorerState.humanizePropertyName
        ? prettyCONSTName(node.label)
        : node.label;
    const selectNode = () => onNodeSelect?.(node);
    const onContextMenuOpen = () => setIsSelectedFromContextMenu(true);
    const onContextMenuClose = () => setIsSelectedFromContextMenu(false);
    if (isRoot) {
        const isExpanded = node.isOpen === true;
        const nodeExpandIcon = isExpanded ? (_jsx(ChevronDownIcon, {})) : (_jsx(ChevronRightIcon, {}));
        return (_jsx(ContextMenu, { content: _jsx(QueryBuilderRelationExplorerContextMenu, { queryBuilderState: queryBuilderState, node: node, accessor: accessor }), menuProps: { elevation: 7 }, onOpen: onContextMenuOpen, onClose: onContextMenuClose, children: _jsxs("div", { className: clsx('tree-view__node__container query-builder-explorer-tree__node__container', {
                    'query-builder-explorer-tree__node__container--selected-from-context-menu': isSelectedFromContextMenu,
                    'query-builder-explorer-tree__node__container--highlighted': explorerState.highlightUsedProperties &&
                        isExplorerTreeNodeAlreadyUsed(node, queryBuilderState),
                }), onClick: selectNode, style: {
                    paddingLeft: `${(level - 1) * (stepPaddingInRem ?? 1) + 0.5}rem`,
                    display: 'flex',
                }, children: [_jsxs("div", { className: "tree-view__node__icon query-builder-explorer-tree__node__icon", children: [_jsx("div", { className: "query-builder-explorer-tree__expand-icon", children: nodeExpandIcon }), _jsx("div", { className: "query-builder-explorer-tree__type-icon", children: getAccessorIcon(accessor) })] }), _jsx("div", { className: "tree-view__node__label query-builder-explorer-tree__node__label query-builder-explorer-tree__node__label--with-action", children: node.label }), _jsx("div", { className: "query-builder-explorer-tree__node__actions", children: _jsx(Tooltip, { arrow: true, classes: {
                                tooltip: 'query-builder__tooltip',
                                arrow: 'query-builder__tooltip__arrow',
                                tooltipPlacementRight: 'query-builder__tooltip--right',
                            }, slotProps: {
                                transition: { timeout: 0 },
                            }, title: _jsxs("div", { className: "query-builder__tooltip__content", children: [_jsxs("div", { className: "query-builder__tooltip__item", children: [_jsx("div", { className: "query-builder__tooltip__item__label", children: "Type" }), _jsx("div", { className: "query-builder__tooltip__item__value", children: accessor.accessorOwnerLabel })] }), _jsxs("div", { className: "query-builder__tooltip__item", children: [_jsx("div", { className: "query-builder__tooltip__item__label", children: "Path" }), _jsx("div", { className: "query-builder__tooltip__item__value", children: getAccessorPath(accessor) })] })] }), children: _jsx("div", { className: "query-builder-explorer-tree__node__action query-builder-explorer-tree__node__info", "data-testid": QUERY_BUILDER_TEST_ID.QUERY_BUILDER_TOOLTIP_ICON, children: _jsx(InfoCircleIcon, {}) }) }) })] }) }));
    }
    // Column node
    const columnNode = isColumn ? node : undefined;
    const nodeTypeIcon = isColumn
        ? renderPropertyTypeIcon(node.type)
        : undefined;
    const columnTypeLabel = columnNode
        ? getColumnTypeLabel(columnNode.column)
        : node.type.path;
    const columnMultiplicity = columnNode?.column.multiplicity;
    const isMultiple = columnMultiplicity !== undefined &&
        (columnMultiplicity.upperBound === undefined ||
            columnMultiplicity.upperBound > 1);
    return (_jsx(ContextMenu, { content: _jsx(QueryBuilderRelationExplorerContextMenu, { queryBuilderState: queryBuilderState, node: node, accessor: accessor }), menuProps: { elevation: 7 }, onOpen: onContextMenuOpen, onClose: onContextMenuClose, children: _jsxs("div", { className: clsx('tree-view__node__container query-builder-explorer-tree__node__container', {
                'query-builder-explorer-tree__node__container--selected-from-context-menu': isSelectedFromContextMenu,
                'query-builder-explorer-tree__node__container--highlighted': explorerState.highlightUsedProperties &&
                    isExplorerTreeNodeAlreadyUsed(node, queryBuilderState),
            }), onClick: selectNode, ref: ref, style: {
                paddingLeft: `${(level - 1) * (stepPaddingInRem ?? 1) + 0.5}rem`,
                display: 'flex',
            }, children: [_jsxs("div", { className: "tree-view__node__icon query-builder-explorer-tree__node__icon", children: [_jsx("div", { className: "query-builder-explorer-tree__expand-icon", children: _jsx("div", {}) }), _jsx("div", { className: "query-builder-explorer-tree__type-icon", children: nodeTypeIcon })] }), _jsxs("div", { className: "tree-view__node__label query-builder-explorer-tree__node__label query-builder-explorer-tree__node__label--with-action", children: [columnLabel, isMultiple && (_jsx("div", { className: "query-builder-explorer-tree__node__label__multiple", title: "Multiple values of this column can cause row explosion", children: "*" }))] }), _jsx("div", { className: "query-builder-explorer-tree__node__actions", children: _jsx(QueryBuilderBaseInfoTooltip, { title: columnLabel, data: [
                            {
                                label: 'Type',
                                value: columnTypeLabel,
                            },
                            {
                                label: 'Column',
                                value: node.label,
                            },
                            ...(columnMultiplicity
                                ? [
                                    {
                                        label: 'Multiplicity',
                                        value: getMultiplicityDescription(columnMultiplicity),
                                    },
                                ]
                                : []),
                        ], children: _jsx("div", { className: "query-builder-explorer-tree__node__action query-builder-explorer-tree__node__info", "data-testid": QUERY_BUILDER_TEST_ID.QUERY_BUILDER_TOOLTIP_ICON, children: _jsx(InfoCircleIcon, {}) }) }) })] }) }));
});
const QueryBuilderRelationTreeNodeView = observer((props) => {
    const { node, level, onNodeSelect, getChildNodes, stepPaddingInRem, innerProps, components, } = props;
    return (_jsxs("div", { className: "tree-view__node__block", children: [_jsx(QueryBuilderRelationNodeContainer, { node: node, level: level + 1, stepPaddingInRem: stepPaddingInRem, onNodeSelect: onNodeSelect, innerProps: innerProps }), node.isOpen &&
                getChildNodes(node).map((childNode) => (_jsx(QueryBuilderRelationTreeNodeView, { node: childNode, level: level + 1, components: components, onNodeSelect: onNodeSelect, getChildNodes: getChildNodes, innerProps: innerProps }, childNode.id)))] }));
});
const QueryBuilderRelationExplorerTree = observer((props) => {
    const { queryBuilderState, accessor } = props;
    // NOTE: we must memoize tree data so node state (e.g. isOpen) persists across re-renders
    const treeData = useMemo(() => buildRelationTreeData(accessor), [accessor]);
    const onNodeSelect = (node) => {
        if (node instanceof QueryBuilderExplorerTreeRelationRootNodeData) {
            node.setIsOpen(!node.isOpen);
        }
    };
    const getChildNodes = (node) => {
        if (node instanceof QueryBuilderExplorerTreeRelationRootNodeData) {
            return node.childrenIds
                .map((id) => treeData.nodes.get(id))
                .filter(isNonNullable);
        }
        return [];
    };
    return (_jsx(TreeView, { components: {
            TreeNodeContainer: QueryBuilderRelationNodeContainer,
            TreeNodeView: QueryBuilderRelationTreeNodeView,
        }, className: "query-builder-explorer-tree__root", treeData: treeData, onNodeSelect: onNodeSelect, getChildNodes: getChildNodes, innerProps: {
            queryBuilderState,
            accessor,
        } }));
});
export const QueryBuilderRelationExplorerPanel = observer((props) => {
    const { queryBuilderState, accessor } = props;
    return (_jsxs("div", { "data-testid": QUERY_BUILDER_TEST_ID.QUERY_BUILDER_EXPLORER, className: "panel query-builder__explorer", children: [_jsx(PanelHeader, { title: "columns" }), _jsxs("div", { className: "panel__content query-builder-explorer-tree__content", children: [_jsx(DragPreviewLayer, { labelGetter: (item) => {
                            const dragNode = item.node;
                            return queryBuilderState.explorerState.humanizePropertyName
                                ? prettyCONSTName(dragNode.label)
                                : dragNode.label;
                        }, types: [QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.RELATION_COLUMN] }), accessor.relationType.columns.length === 0 ? (_jsx(BlankPanelContent, { children: "No columns" })) : (_jsx(QueryBuilderRelationExplorerTree, { queryBuilderState: queryBuilderState, accessor: accessor }))] })] }));
});
//# sourceMappingURL=QueryBuilderRelationExplorerPanel.js.map