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 { shallow } from "zustand/shallow";
import { useSafeLingui } from "../../../i18n/index.js";
import { NODE_BADGE_INSET_SQUARE, NODE_BADGE_SIZE } from "../../constants.js";
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, getContainerResizeMinimums } 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 { areNodePropsEqualIgnoringPosition } from "../../utils/nodePropsEqual.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 { CanvasTooltip } from "../CanvasTooltip.js";
import { NodeToolbar } from "../Toolbar/index.js";
import { resolveContainerHandleGroups } from "./LoopNode.helpers.js";
import { LoopNodeExecutionCount } from "./LoopNodeExecutionCount.js";
const DEFAULT_LOOP_ICON = 'repeat';
const EMPTY_DATA = {};
const LOOP_HEADER_ADORNMENT_GAP = 8;
const LOOP_HEADER_ADORNMENT_PADDING = NODE_BADGE_INSET_SQUARE + NODE_BADGE_SIZE + LOOP_HEADER_ADORNMENT_GAP;
const RESIZE_CONTROLS = [
    {
        position: 'top-left',
        widthSide: 'left',
        heightSide: 'top',
        cursor: 'nwse-resize',
        indicatorClassName: 'top-[-4px] left-[-4px]'
    },
    {
        position: 'top-right',
        widthSide: 'right',
        heightSide: 'top',
        cursor: 'nesw-resize',
        indicatorClassName: 'top-[-4px] right-[-4px]'
    },
    {
        position: 'bottom-left',
        widthSide: 'left',
        heightSide: 'bottom',
        cursor: 'nesw-resize',
        indicatorClassName: 'bottom-[-4px] left-[-4px]'
    },
    {
        position: 'bottom-right',
        widthSide: 'right',
        heightSide: 'bottom',
        cursor: 'nwse-resize',
        indicatorClassName: 'bottom-[-4px] right-[-4px]'
    }
];
const RESIZE_CONTROL_STYLE = {
    background: 'transparent',
    border: 'none',
    zIndex: 100
};
const DEFAULT_RESIZE_MINIMUMS = {
    left: DEFAULT_CONTAINER_MIN_WIDTH,
    right: DEFAULT_CONTAINER_MIN_WIDTH,
    top: DEFAULT_CONTAINER_MIN_HEIGHT,
    bottom: DEFAULT_CONTAINER_MIN_HEIGHT
};
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.parentLookup.get(id)?.size ?? 0) > 0, [
        id,
        enabled
    ]));
}
function useContainerResizeMinimums(id, width, height, enabled) {
    return useStore(useCallback((state)=>{
        if (!enabled) return DEFAULT_RESIZE_MINIMUMS;
        return getContainerResizeMinimums({
            id,
            width,
            height
        }, Array.from(state.parentLookup.get(id)?.values() ?? []));
    }, [
        enabled,
        height,
        id,
        width
    ]), shallow);
}
function useContainerNodeInternalsRefresh(id, handleGroups, width, height) {
    const updateNodeInternals = useUpdateNodeInternals();
    useEffect(()=>{
        const frameId = requestAnimationFrame(()=>{
            updateNodeInternals(id);
        });
        return ()=>{
            cancelAnimationFrame(frameId);
        };
    }, [
        id,
        handleGroups,
        updateNodeInternals,
        width,
        height
    ]);
}
function resolveLoopHandleConfigurations(manifestHandleConfigurations, data) {
    if (Array.isArray(data.handleConfigurations)) return data.handleConfigurations;
    return manifestHandleConfigurations ?? [];
}
function LoopNodeComponent(props) {
    const { id, type, data, selected = false, dragging = false, width = 0, height = 0, onAddFirstChild, onResize, onResizeStart, onResizeEnd, toolbarConfig: toolbarConfigProp, adornments: adornmentsProp, executionStatusOverride, suggestionType: suggestionTypeProp, iterationPillState: iterationPillStateProp } = props;
    const nodeTypeRegistry = useOptionalNodeTypeRegistry();
    const { _ } = useSafeLingui();
    const [isHovered, setIsHovered] = useState(false);
    const [isResizing, setIsResizing] = 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 ?? _({
        id: 'loop-node.title',
        message: 'Loop'
    });
    const displayIcon = display.icon ?? DEFAULT_LOOP_ICON;
    const isParallel = true === resolvedData.parallel;
    const label = isParallel ? _({
        id: 'loop-node.mode.parallel',
        message: 'Parallel'
    }) : _({
        id: 'loop-node.mode.sequential',
        message: 'Sequential'
    });
    const addNodeToLoopLabel = _({
        id: 'loop-node.add-node',
        message: 'Add node to loop'
    });
    const isDropTarget = true === resolvedData.isDropTarget;
    const containerWidth = width || DEFAULT_CONTAINER_WIDTH;
    const containerHeight = height || DEFAULT_CONTAINER_HEIGHT;
    const resizeControlsMounted = isDesignMode && !dragging;
    const resizeControlsVisible = resizeControlsMounted && (selected || isResizing);
    const resizeMinimumsEnabled = resizeControlsMounted && (selected || isHovered || isResizing);
    const resizeMinimums = useContainerResizeMinimums(id, containerWidth, containerHeight, resizeMinimumsEnabled);
    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, {
                hideExecutionStatusAdornment: true
            }),
            ...adornmentsProp ?? {}
        }), [
        adornmentsProp,
        statusContext
    ]);
    const hasTopLeftAdornment = !!adornments.topLeft;
    const hasTopRightAdornment = !!adornments.topRight;
    const resolvedHandleGroups = useMemo(()=>{
        const handleConfigurations = resolveLoopHandleConfigurations(manifest?.handleConfiguration, resolvedData);
        return resolveHandles(handleConfigurations, {
            ...resolvedData,
            nodeId: id
        });
    }, [
        manifest?.handleConfiguration,
        id,
        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 handleResizeStart = useCallback(()=>{
        setIsResizing(true);
        onResizeStart?.();
    }, [
        onResizeStart
    ]);
    const handleResizeEnd = useCallback(()=>{
        setIsResizing(false);
        if (onResizeEnd) queueMicrotask(onResizeEnd);
    }, [
        onResizeEnd
    ]);
    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 showEmptyStateButton = isDesignMode && !hasChildNodes && !!onAddFirstChild;
    const interactionState = resolveInteractionState(dragging, selected, isHovered);
    const activeStatus = suggestionType ?? validationState?.validationStatus ?? executionStatus;
    const statusBorder = getStatusBorder(activeStatus);
    const hasStatusBorder = statusBorder.length > 0;
    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', statusBorder, isHovered && 'shadow-(--canvas-node-shadow-hover)', isHovered && !hasStatusBorder && '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: [
            /*#__PURE__*/ jsxs("div", {
                className: "absolute inset-0 isolate flex flex-col overflow-hidden rounded-[19px]",
                children: [
                    /*#__PURE__*/ jsx(Header, {
                        title: displayTitle,
                        icon: displayIcon,
                        loading: isLoading,
                        isParallel: isParallel,
                        label: label,
                        iterationPillState: iterationPillStateProp,
                        nodeWidth: containerWidth,
                        hasTopLeftAdornment: hasTopLeftAdornment,
                        hasTopRightAdornment: hasTopRightAdornment
                    }),
                    /*#__PURE__*/ jsx(LoopNode_BodyFrame, {
                        isEmpty: showEmptyStateButton,
                        isLoading: isLoading
                    })
                ]
            }),
            ADORNMENT_SLOT_POSITIONS.map((slot)=>adornments?.[slot] ? /*#__PURE__*/ jsx(BaseBadgeSlot, {
                    position: ADORNMENT_SLOT_SHAPES[slot],
                    shape: "rectangle",
                    children: adornments[slot]
                }, slot) : null),
            /*#__PURE__*/ jsx(LoopNode_ResizeCornerIndicators, {
                visible: resizeControlsVisible
            }),
            resizeControlsMounted ? /*#__PURE__*/ jsx(LoopNode_ResizeControls, {
                minimums: resizeMinimums,
                onResize: handleResize,
                onResizeStart: handleResizeStart,
                onResizeEnd: handleResizeEnd
            }) : null,
            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, {
                    label: addNodeToLoopLabel,
                    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, areNodePropsEqualIgnoringPosition);
function Header({ title, icon, loading, isParallel, label, iterationPillState, nodeWidth, hasTopLeftAdornment, hasTopRightAdornment }) {
    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;
    const headerStyle = hasTopLeftAdornment || hasTopRightAdornment ? {
        paddingLeft: hasTopLeftAdornment ? LOOP_HEADER_ADORNMENT_PADDING : void 0,
        paddingRight: hasTopRightAdornment ? LOOP_HEADER_ADORNMENT_PADDING : void 0
    } : void 0;
    return /*#__PURE__*/ jsxs("div", {
        className: cn('relative z-10 flex shrink-0 cursor-grab items-center justify-between gap-2.5 rounded-t-[18px]', '-mb-2.5 bg-surface-overlay px-3.5 pb-2.5 pt-2.5 text-foreground', 'active:cursor-grabbing'),
        style: headerStyle,
        "data-testid": "loop-node-header",
        children: [
            /*#__PURE__*/ jsxs("div", {
                className: "flex min-w-0 items-center gap-2.5",
                children: [
                    iconContent,
                    titleContent
                ]
            }),
            /*#__PURE__*/ jsxs("div", {
                className: "flex shrink-0 items-center gap-2",
                children: [
                    iterationPillState ? /*#__PURE__*/ jsx(LoopNodeExecutionCount, {
                        state: iterationPillState,
                        size: nodeWidth >= 400 ? 'full' : nodeWidth >= 260 ? 'compact' : 'minimal'
                    }) : null,
                    /*#__PURE__*/ jsxs("span", {
                        className: "flex h-6 shrink-0 items-center gap-1 rounded-full border border-border bg-surface px-2.5 text-[11px] font-semibold leading-4 text-foreground shadow-sm",
                        children: [
                            /*#__PURE__*/ jsx("span", {
                                className: cn('flex shrink-0', isParallel && 'rotate-90'),
                                "aria-hidden": true,
                                children: /*#__PURE__*/ jsx(CanvasIcon, {
                                    icon: "text-align-justify",
                                    size: 12
                                })
                            }),
                            label
                        ]
                    })
                ]
            })
        ]
    });
}
function EmptyState({ label, onAddFirstChild }) {
    return /*#__PURE__*/ jsx(CanvasTooltip, {
        content: label,
        placement: "top",
        children: /*#__PURE__*/ jsx("button", {
            type: "button",
            onClick: onAddFirstChild,
            "aria-label": label,
            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
            })
        })
    });
}
const LoopNode_BodyFrame = /*#__PURE__*/ memo(function({ 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 bg-transparent', 'shadow-[0_0_0_200px_var(--surface-overlay)]', 'pointer-events-none'),
        children: isLoading ? /*#__PURE__*/ jsx("div", {
            className: "m-6 h-14 w-full animate-pulse rounded-[18px] bg-(--canvas-background-overlay)"
        }) : null
    });
});
const LoopNode_ResizeControls = /*#__PURE__*/ memo(function({ minimums = DEFAULT_RESIZE_MINIMUMS, onResize, onResizeStart, onResizeEnd }) {
    return /*#__PURE__*/ jsx(Fragment, {
        children: RESIZE_CONTROLS.map(({ position, widthSide, heightSide, cursor })=>/*#__PURE__*/ jsx(NodeResizeControl, {
                style: RESIZE_CONTROL_STYLE,
                position: position,
                minWidth: minimums[widthSide],
                minHeight: minimums[heightSide],
                onResizeStart: onResizeStart,
                onResize: onResize,
                onResizeEnd: onResizeEnd,
                children: /*#__PURE__*/ jsx("div", {
                    className: "absolute bottom-0 right-0 h-5 w-5 pointer-events-auto",
                    style: {
                        cursor
                    }
                })
            }, position))
    });
});
const LoopNode_ResizeCornerIndicators = /*#__PURE__*/ memo(function({ visible }) {
    return /*#__PURE__*/ jsx(Fragment, {
        children: RESIZE_CONTROLS.map(({ position, indicatorClassName })=>/*#__PURE__*/ jsx("div", {
                "aria-hidden": true,
                "data-testid": `loop-resize-corner-indicator-${position}`,
                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 };
