import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import { NodeResizeControl, useStore, useUpdateNodeInternals } from "../../xyflow/react.js";
import { cn } from "@uipath/apollo-wind";
import { memo, useCallback, useEffect, useMemo, useState } from "react";
import { useOptionalNodeTypeRegistry } from "../../core/index.js";
import { useElementValidationStatus, useNodeExecutionState } from "../../hooks/index.js";
import { resolveAdornments } from "../../utils/adornment-resolver.js";
import { DEFAULT_CONTAINER_HEIGHT, DEFAULT_CONTAINER_MIN_HEIGHT, DEFAULT_CONTAINER_MIN_WIDTH, DEFAULT_CONTAINER_WIDTH } from "../../utils/container.js";
import { CanvasIcon } from "../../utils/icon-registry.js";
import { resolveDisplay, resolveHandles } from "../../utils/manifest-resolver.js";
import { selectIsConnecting, snapToGrid } from "../../utils/NodeUtils.js";
import { resolveToolbar } from "../../utils/toolbar-resolver.js";
import { useBaseCanvasMode } from "../BaseCanvas/BaseCanvasModeProvider.js";
import { useConnectedHandles } from "../BaseCanvas/ConnectedHandlesContext.js";
import { useSelectionState } from "../BaseCanvas/SelectionStateContext.js";
import { BaseBadgeSlot } from "../BaseNode/BaseNodeBadgeSlot.js";
import { getStatusBorder } from "../BaseNode/BaseNodeContainer.js";
import { MissingManifestNode } from "../BaseNode/BaseNodeMissingManifest.js";
import { ButtonHandles } from "../ButtonHandle/index.js";
import { NodeToolbar } from "../Toolbar/index.js";
import { resolveContainerHandleGroups } from "./LoopNode.helpers.js";
const DEFAULT_LOOP_ICON = 'repeat';
const DEFAULT_LOOP_TITLE = 'Loop';
const EMPTY_DATA = {};
const RESIZE_CONTROLS = [
    {
        position: 'top-left',
        cursor: 'nwse-resize',
        indicatorClassName: 'top-[-4px] left-[-4px]'
    },
    {
        position: 'top-right',
        cursor: 'nesw-resize',
        indicatorClassName: 'top-[-4px] right-[-4px]'
    },
    {
        position: 'bottom-left',
        cursor: 'nesw-resize',
        indicatorClassName: 'bottom-[-4px] left-[-4px]'
    },
    {
        position: 'bottom-right',
        cursor: 'nwse-resize',
        indicatorClassName: 'bottom-[-4px] right-[-4px]'
    }
];
const RESIZE_CONTROL_STYLE = {
    background: 'transparent',
    border: 'none',
    zIndex: 100
};
const ADORNMENT_SLOT_POSITIONS = [
    'topLeft',
    'topRight',
    'bottomLeft',
    'bottomRight'
];
const ADORNMENT_SLOT_SHAPES = {
    topLeft: 'top-left',
    topRight: 'top-right',
    bottomLeft: 'bottom-left',
    bottomRight: 'bottom-right'
};
function resolveInteractionState(dragging, selected, isHovered) {
    if (dragging) return 'drag';
    if (selected) return 'selected';
    if (isHovered) return 'hover';
    return 'default';
}
function useHasChildNodes(id, enabled) {
    return useStore(useCallback((state)=>!enabled || state.nodes.some((node)=>node.parentId === id), [
        id,
        enabled
    ]));
}
function useContainerNodeInternalsRefresh(id, handleGroups, width, height) {
    const updateNodeInternals = useUpdateNodeInternals();
    useEffect(()=>{
        const frameId = requestAnimationFrame(()=>{
            updateNodeInternals(id);
        });
        return ()=>{
            cancelAnimationFrame(frameId);
        };
    }, [
        id,
        handleGroups,
        updateNodeInternals,
        width,
        height
    ]);
}
function LoopNodeComponent(props) {
    const { id, type, data, selected = false, dragging = false, width = 0, height = 0, onAddFirstChild, onResize, toolbarConfig: toolbarConfigProp, adornments: adornmentsProp, executionStatusOverride, suggestionType: suggestionTypeProp } = props;
    const nodeTypeRegistry = useOptionalNodeTypeRegistry();
    const [isHovered, setIsHovered] = useState(false);
    const resolvedData = data ?? EMPTY_DATA;
    const isLoading = !!resolvedData.loading;
    const suggestionType = suggestionTypeProp ?? resolvedData.suggestionType;
    const manifest = useMemo(()=>nodeTypeRegistry?.getManifest(type), [
        nodeTypeRegistry,
        type
    ]);
    const { mode } = useBaseCanvasMode();
    const isDesignMode = 'design' === mode;
    const connectedHandleIds = useConnectedHandles(id);
    const { multipleNodesSelected } = useSelectionState();
    const isConnecting = useStore(selectIsConnecting);
    const hasChildNodes = useHasChildNodes(id, isDesignMode && !!onAddFirstChild);
    const executionState = useNodeExecutionState(id);
    const validationState = useElementValidationStatus(id);
    const statusContext = useMemo(()=>({
            nodeId: id,
            executionState: executionStatusOverride ?? executionState,
            validationState,
            isConnecting,
            isSelected: selected,
            isDragging: dragging,
            mode
        }), [
        dragging,
        executionStatusOverride,
        executionState,
        id,
        isConnecting,
        mode,
        selected,
        validationState
    ]);
    const executionStatus = executionStatusOverride ?? ('string' == typeof executionState ? executionState : executionState?.status);
    const display = useMemo(()=>resolveDisplay(manifest?.display, {
            ...resolvedData,
            nodeId: id
        }), [
        manifest?.display,
        id,
        resolvedData
    ]);
    const displayTitle = display.label ?? DEFAULT_LOOP_TITLE;
    const displayIcon = display.icon ?? DEFAULT_LOOP_ICON;
    const isParallel = true === resolvedData.parallel;
    const isDropTarget = true === resolvedData.isDropTarget;
    const containerWidth = width || DEFAULT_CONTAINER_WIDTH;
    const containerHeight = height || DEFAULT_CONTAINER_HEIGHT;
    const nodeSizeStyle = {
        width: containerWidth,
        height: containerHeight,
        minWidth: DEFAULT_CONTAINER_MIN_WIDTH,
        minHeight: DEFAULT_CONTAINER_MIN_HEIGHT
    };
    const toolbarConfig = useMemo(()=>{
        if (void 0 !== toolbarConfigProp) return null === toolbarConfigProp ? void 0 : toolbarConfigProp;
        return manifest ? resolveToolbar(manifest, statusContext, data) : void 0;
    }, [
        data,
        manifest,
        statusContext,
        toolbarConfigProp
    ]);
    const adornments = useMemo(()=>({
            ...resolveAdornments(statusContext),
            ...adornmentsProp ?? {}
        }), [
        adornmentsProp,
        statusContext
    ]);
    const resolvedHandleGroups = useMemo(()=>manifest ? resolveHandles(manifest.handleConfiguration, resolvedData) : [], [
        manifest,
        resolvedData
    ]);
    const containerHandleGroups = useMemo(()=>resolveContainerHandleGroups(resolvedHandleGroups), [
        resolvedHandleGroups
    ]);
    useContainerNodeInternalsRefresh(id, containerHandleGroups, containerWidth, containerHeight);
    const handleResize = useCallback((_event, params)=>{
        onResize?.({
            width: snapToGrid(params.width),
            height: snapToGrid(params.height)
        });
    }, [
        onResize
    ]);
    const handleEmptyClick = useCallback(()=>{
        onAddFirstChild?.();
    }, [
        onAddFirstChild
    ]);
    const handleMouseEnter = useCallback(()=>setIsHovered(true), []);
    const handleMouseLeave = useCallback(()=>setIsHovered(false), []);
    const handleHandleAction = useCallback((_event)=>{
        setIsHovered(false);
    }, []);
    const shouldShowHandles = (isConnecting || selected || isHovered) && !dragging;
    const showHandleAddButtons = isDesignMode && !multipleNodesSelected && !isConnecting && !dragging;
    const showResizeControls = selected && !dragging && isDesignMode;
    const showEmptyStateButton = isDesignMode && !hasChildNodes && !!onAddFirstChild;
    const interactionState = resolveInteractionState(dragging, selected, isHovered);
    if (!manifest) return /*#__PURE__*/ jsx("div", {
        className: "relative",
        style: nodeSizeStyle,
        onMouseEnter: handleMouseEnter,
        onMouseLeave: handleMouseLeave,
        children: /*#__PURE__*/ jsx(MissingManifestNode, {
            type: type,
            isSelected: selected,
            isHovered: isHovered,
            interactionState: interactionState
        })
    });
    return /*#__PURE__*/ jsxs("div", {
        "data-loop-container": true,
        "data-selected": selected ? 'true' : 'false',
        "data-execution-status": executionStatus,
        "data-interaction-state": interactionState,
        "data-suggestion-type": suggestionType,
        "data-validation-status": validationState?.validationStatus,
        "aria-busy": resolvedData.loading || void 0,
        className: cn('group/loop-shell relative box-border flex h-full w-full flex-col overflow-visible rounded-[20px] border bg-transparent', 'transition-[border-color,box-shadow,opacity] shadow-(--canvas-node-shadow-rest)', 'border-border-subtle', getStatusBorder(suggestionType ?? validationState?.validationStatus ?? executionStatus), isHovered && 'shadow-(--canvas-node-shadow-hover) border-border-hover', selected && 'outline outline-2 outline-foreground-accent-muted', isDropTarget && 'bg-surface-hover outline outline-2 outline-brand', 'drag' === interactionState && 'cursor-grabbing shadow-(--canvas-node-shadow-lifted)'),
        style: {
            ...nodeSizeStyle,
            ...display.background ? {
                background: display.background
            } : {}
        },
        onMouseEnter: handleMouseEnter,
        onMouseLeave: handleMouseLeave,
        children: [
            ADORNMENT_SLOT_POSITIONS.map((slot)=>adornments?.[slot] ? /*#__PURE__*/ jsx(BaseBadgeSlot, {
                    position: ADORNMENT_SLOT_SHAPES[slot],
                    shape: "rectangle",
                    children: adornments[slot]
                }, slot) : null),
            /*#__PURE__*/ jsx(ResizeCornerIndicators, {
                visible: showResizeControls
            }),
            showResizeControls ? /*#__PURE__*/ jsx(ResizeControls, {
                onResize: handleResize
            }) : null,
            /*#__PURE__*/ jsx(Header, {
                title: displayTitle,
                icon: displayIcon,
                loading: isLoading,
                isParallel: isParallel
            }),
            /*#__PURE__*/ jsx(BodyFrame, {
                isEmpty: showEmptyStateButton,
                isLoading: isLoading
            }),
            showEmptyStateButton ? /*#__PURE__*/ jsx("div", {
                className: cn('pointer-events-none absolute left-1/2 top-1/2', '-translate-x-1/2 -translate-y-1/2'),
                children: /*#__PURE__*/ jsx(EmptyState, {
                    onAddFirstChild: handleEmptyClick
                })
            }) : null,
            toolbarConfig && /*#__PURE__*/ jsx(NodeToolbar, {
                nodeId: id,
                config: toolbarConfig,
                expanded: selected || isHovered,
                hidden: dragging || multipleNodesSelected,
                portalToNodeOverlay: true
            }),
            /*#__PURE__*/ jsx(HandleGroups, {
                nodeId: id,
                groups: containerHandleGroups,
                selected: selected,
                hovered: isHovered,
                shouldShowHandles: shouldShowHandles,
                showAddButton: showHandleAddButtons,
                showNotches: shouldShowHandles,
                nodeWidth: containerWidth,
                nodeHeight: containerHeight,
                connectedHandleIds: connectedHandleIds,
                onHandleAction: handleHandleAction
            })
        ]
    });
}
const LoopNode = /*#__PURE__*/ memo(LoopNodeComponent);
function Header({ title, icon, loading, isParallel }) {
    const titleContent = loading ? /*#__PURE__*/ jsx("div", {
        className: "h-5 w-28 animate-pulse rounded bg-(--canvas-background-overlay)"
    }) : /*#__PURE__*/ jsx("span", {
        className: "truncate text-[15px] font-semibold leading-5 tracking-normal",
        children: title
    });
    const iconContent = loading ? /*#__PURE__*/ jsx("div", {
        className: "h-4 w-4 shrink-0 animate-pulse rounded bg-(--canvas-background-overlay)"
    }) : icon ? /*#__PURE__*/ jsx("span", {
        className: "shrink-0 text-foreground",
        "aria-hidden": true,
        children: /*#__PURE__*/ jsx(CanvasIcon, {
            icon: icon,
            size: 16
        })
    }) : null;
    return /*#__PURE__*/ jsxs("div", {
        className: "flex shrink-0 cursor-grab items-center justify-between gap-2.5 px-3.5 pt-2.5 text-foreground active:cursor-grabbing",
        "data-testid": "loop-node-header",
        children: [
            /*#__PURE__*/ jsxs("div", {
                className: "flex min-w-0 items-center gap-2.5",
                children: [
                    iconContent,
                    titleContent
                ]
            }),
            /*#__PURE__*/ jsxs("span", {
                className: "flex shrink-0 items-center gap-1 rounded-full border border-border-subtle bg-transparent px-2.5 py-0.5 text-[11px] font-semibold leading-4 text-foreground",
                children: [
                    /*#__PURE__*/ jsx("span", {
                        className: cn('flex shrink-0', isParallel && 'rotate-90'),
                        "aria-hidden": true,
                        children: /*#__PURE__*/ jsx(CanvasIcon, {
                            icon: "align-justify",
                            size: 11
                        })
                    }),
                    isParallel ? 'Parallel' : 'Sequential'
                ]
            })
        ]
    });
}
function EmptyState({ onAddFirstChild }) {
    return /*#__PURE__*/ jsx("button", {
        type: "button",
        onClick: onAddFirstChild,
        "aria-label": "Add node to loop",
        className: cn('nodrag nopan', 'pointer-events-auto flex h-8 w-8 items-center justify-center rounded-xl', 'border border-border bg-surface-overlay text-foreground', 'shadow-(--canvas-node-shadow-lifted)', 'transition-colors', 'hover:bg-surface-hover hover:border-brand'),
        children: /*#__PURE__*/ jsx(CanvasIcon, {
            icon: "plus",
            size: 14
        })
    });
}
function BodyFrame({ isEmpty, isLoading }) {
    return /*#__PURE__*/ jsx("div", {
        "data-testid": "loop-body-frame",
        "data-empty": isEmpty ? 'true' : 'false',
        className: cn('relative m-2.5 flex flex-1 rounded-xl border-[1.5px] border-dashed border-border-subtle bg-transparent', 'pointer-events-none'),
        children: isLoading ? /*#__PURE__*/ jsx("div", {
            className: "m-6 h-14 w-full animate-pulse rounded-[18px] bg-(--canvas-background-overlay)"
        }) : null
    });
}
function ResizeControls({ onResize }) {
    return /*#__PURE__*/ jsx(Fragment, {
        children: RESIZE_CONTROLS.map(({ position, cursor })=>/*#__PURE__*/ jsx(NodeResizeControl, {
                style: RESIZE_CONTROL_STYLE,
                position: position,
                minWidth: DEFAULT_CONTAINER_MIN_WIDTH,
                minHeight: DEFAULT_CONTAINER_MIN_HEIGHT,
                onResize: onResize,
                children: /*#__PURE__*/ jsx("div", {
                    className: "absolute bottom-0 right-0 h-5 w-5 pointer-events-auto",
                    style: {
                        cursor
                    }
                })
            }, position))
    });
}
function ResizeCornerIndicators({ visible }) {
    return /*#__PURE__*/ jsx(Fragment, {
        children: RESIZE_CONTROLS.map(({ position, indicatorClassName })=>/*#__PURE__*/ jsx("div", {
                "aria-hidden": true,
                className: cn('pointer-events-none absolute h-2 w-2 rounded-full bg-brand transition-opacity', indicatorClassName, visible ? 'opacity-100' : 'opacity-0')
            }, position))
    });
}
function HandleGroups({ groups, ...handleGroupProps }) {
    if (0 === groups.length) return null;
    return /*#__PURE__*/ jsx(Fragment, {
        children: groups.map((group, groupIndex)=>/*#__PURE__*/ jsx(HandleGroup, {
                ...handleGroupProps,
                group: group
            }, `${group.boundary}:${group.position}:${groupIndex}`))
    });
}
function HandleGroup({ nodeId, group, selected, hovered, shouldShowHandles, showAddButton, showNotches, nodeWidth, nodeHeight, connectedHandleIds, onHandleAction }) {
    const groupVisible = shouldShowHandles && (group.visible ?? true);
    const position = group.position;
    const enhancedHandles = useMemo(()=>group.handles.map((handle)=>{
            const showHandle = connectedHandleIds.has(handle.id) || groupVisible;
            if ('inner' === group.boundary) return {
                ...handle,
                showHandle,
                showButton: false,
                onAction: void 0
            };
            return {
                ...handle,
                showHandle,
                showButton: handle.showButton,
                onAction: handle.onAction ?? onHandleAction
            };
        }), [
        group.boundary,
        group.handles,
        connectedHandleIds,
        groupVisible,
        onHandleAction
    ]);
    return /*#__PURE__*/ jsx(ButtonHandles, {
        nodeId: nodeId,
        handles: enhancedHandles,
        position: position,
        connectionPosition: group.connectionPosition,
        selected: selected,
        hovered: hovered,
        showAddButton: showAddButton,
        showNotches: showNotches,
        customPositionAndOffsets: group.customPositionAndOffsets,
        nodeWidth: nodeWidth,
        nodeHeight: nodeHeight,
        portalActions: 'outer' === group.boundary
    });
}
export { LoopNode };
