import { jsx } from "react/jsx-runtime";
import { useReactFlow } from "../../xyflow/react.js";
import { useCallback, useEffect, useRef } from "react";
import { FLOATING_CANVAS_PANEL_OFFSET, PREVIEW_NODE_ID } from "../../constants.js";
import { useOptionalNodeTypeRegistry } from "../../core/index.js";
import { useCanvasNodeLayout } from "../../hooks/useCanvasNodeLayout.js";
import { usePreviewNode } from "../../hooks/usePreviewNode.js";
import { isPreviewEdge } from "../../utils/createPreviewNode.js";
import { FloatingCanvasPanel } from "../FloatingCanvasPanel/index.js";
import { alignNodeToPreview, getOriginalEdge, placeAddedNode } from "./AddNodeManager.helpers.js";
import { AddNodePanel } from "./AddNodePanel.js";
const AddNodeManager = ({ initializing, customPanel: CustomPanel, createNodeData, onBeforeNodeAdded, onNodeAdded, ignoredNodeTypes })=>{
    const reactFlowInstance = useReactFlow();
    const registry = useOptionalNodeTypeRegistry();
    const nodeLayout = useCanvasNodeLayout();
    const { previewNode, previewNodeConnectionInfo } = usePreviewNode();
    const lastPreviewNodeRef = useRef(null);
    const restoreEdgesRef = useRef(null);
    useEffect(()=>{
        if (!previewNode && lastPreviewNodeRef.current) {
            reactFlowInstance.setNodes((nodes)=>nodes.filter((n)=>n.id !== PREVIEW_NODE_ID));
            reactFlowInstance.setEdges((edges)=>{
                const filteredEdges = edges.filter((edge)=>!isPreviewEdge(edge));
                const restoredEdges = restoreEdgesRef.current ? [
                    ...filteredEdges,
                    ...restoreEdgesRef.current
                ] : filteredEdges;
                restoreEdgesRef.current = null;
                return restoredEdges;
            });
        } else if (previewNode && !restoreEdgesRef.current) {
            const originalEdge = getOriginalEdge(previewNode);
            restoreEdgesRef.current = originalEdge ? [
                originalEdge
            ] : null;
        }
        lastPreviewNodeRef.current = previewNode || null;
    }, [
        previewNode,
        reactFlowInstance
    ]);
    const handleClose = useCallback(()=>{
        reactFlowInstance.setNodes((nodes)=>nodes.map((n)=>n.id === PREVIEW_NODE_ID ? {
                    ...n,
                    selected: false
                } : n));
    }, [
        reactFlowInstance
    ]);
    const handleNodeSelect = useCallback((nodeItem)=>{
        const currentPreviewNode = reactFlowInstance.getNode(PREVIEW_NODE_ID);
        if (!currentPreviewNode || !previewNodeConnectionInfo || 0 === previewNodeConnectionInfo.length) return;
        const newNodeId = `${nodeItem.data.type}-${Date.now()}`;
        const baseNodeData = createNodeData ? createNodeData(nodeItem) : {
            label: nodeItem.name,
            subLabel: nodeItem.description
        };
        const nodeData = currentPreviewNode.data?.useSmartHandles ? {
            ...baseNodeData,
            useSmartHandles: true
        } : baseNodeData;
        const previewNodeScope = currentPreviewNode.parentId ? {
            parentId: currentPreviewNode.parentId,
            extent: currentPreviewNode.extent
        } : {};
        const newNodeManifest = registry?.getManifest(nodeItem.data.type);
        const newNode = alignNodeToPreview({
            id: newNodeId,
            type: nodeItem.data.type,
            position: currentPreviewNode.position,
            selected: true,
            data: nodeData,
            ...previewNodeScope
        }, currentPreviewNode, previewNodeConnectionInfo, newNodeManifest);
        const newEdges = [];
        const previewEdgeIds = new Set();
        for (const connectionInfoItem of previewNodeConnectionInfo){
            const newNodeHandleType = connectionInfoItem.addNewNodeAsSource ? 'source' : 'target';
            const newNodeDefaultHandle = newNodeManifest ? registry?.getDefaultHandle(newNodeManifest.nodeType, newNodeHandleType) : void 0;
            const newNodeHandleId = newNodeDefaultHandle?.id;
            const edgeSourceTargetData = connectionInfoItem.addNewNodeAsSource ? {
                source: newNode.id,
                sourceHandle: newNodeHandleId,
                target: connectionInfoItem.existingNodeId,
                targetHandle: connectionInfoItem.existingHandleId
            } : {
                source: connectionInfoItem.existingNodeId,
                sourceHandle: connectionInfoItem.existingHandleId,
                target: newNode.id,
                targetHandle: newNodeHandleId
            };
            const newEdgeId = `edge_${edgeSourceTargetData.source}-${edgeSourceTargetData.sourceHandle}-${edgeSourceTargetData.target}-${edgeSourceTargetData.targetHandle}`;
            newEdges.push({
                id: newEdgeId,
                ...edgeSourceTargetData,
                type: 'default'
            });
            previewEdgeIds.add(connectionInfoItem.previewEdgeId);
        }
        const { newNode: finalNode, newEdges: finalEdges } = onBeforeNodeAdded?.(newNode, newEdges) ?? {
            newNode,
            newEdges
        };
        const placementEdges = reactFlowInstance.getEdges();
        let placedNode = finalNode;
        reactFlowInstance.setNodes((nodes)=>{
            const newNodes = [
                ...nodes.filter((n)=>n.id !== PREVIEW_NODE_ID).map((n)=>({
                        ...n,
                        selected: false
                    })),
                finalNode
            ];
            const placement = placeAddedNode({
                nodes: newNodes,
                edges: placementEdges,
                previewNode: currentPreviewNode,
                insertedNode: finalNode,
                layout: nodeLayout,
                ignoredNodeTypes
            });
            placedNode = placement.insertedNode;
            return placement.nodes;
        });
        reactFlowInstance.setEdges((edges)=>[
                ...edges.filter((edge)=>!previewEdgeIds.has(edge.id) && !isPreviewEdge(edge)),
                ...finalEdges
            ]);
        restoreEdgesRef.current = null;
        const [firstConnection] = previewNodeConnectionInfo;
        if (firstConnection) {
            const firstMaterializedEdge = finalEdges.find((edge)=>edge.source === placedNode.id || edge.target === placedNode.id);
            const firstEdgeData = firstConnection.addNewNodeAsSource ? {
                source: placedNode.id,
                sourceHandle: firstMaterializedEdge?.sourceHandle ?? 'output'
            } : {
                source: firstConnection.existingNodeId,
                sourceHandle: firstConnection.existingHandleId
            };
            onNodeAdded?.(firstEdgeData.source, firstEdgeData.sourceHandle, placedNode);
        }
        lastPreviewNodeRef.current = null;
    }, [
        previewNodeConnectionInfo,
        reactFlowInstance,
        registry,
        nodeLayout,
        createNodeData,
        onBeforeNodeAdded,
        onNodeAdded,
        ignoredNodeTypes
    ]);
    if (!previewNode || !previewNodeConnectionInfo || 0 === previewNodeConnectionInfo.length) return null;
    return /*#__PURE__*/ jsx(FloatingCanvasPanel, {
        open: !!previewNode,
        nodeId: PREVIEW_NODE_ID,
        placement: "right-start",
        offset: FLOATING_CANVAS_PANEL_OFFSET,
        scrollableContent: !!CustomPanel,
        children: CustomPanel ? /*#__PURE__*/ jsx(CustomPanel, {
            onNodeSelect: (item)=>handleNodeSelect(item),
            onClose: handleClose
        }) : /*#__PURE__*/ jsx(AddNodePanel, {
            loading: initializing,
            onNodeSelect: handleNodeSelect,
            onClose: handleClose
        })
    });
};
export { AddNodeManager };
