"use client";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
import { ReactFlow, Controls, MiniMap, Background, BackgroundVariant, MarkerType, useReactFlow, ReactFlowProvider, } from "@xyflow/react";
import { cn } from "@stigmer/theme";
import { WorkflowNode } from "./WorkflowNode.js";
import { CanvasTransitionEdge } from "./CanvasTransitionEdge.js";
import { CANVAS_TASK_NODE_TYPE, CANVAS_TRANSITION_EDGE_TYPE } from "./workflow-graph-conversions.js";
import { WorkflowGraphModeProvider } from "./WorkflowGraphModeContext.js";
import { useWorkflowExecutionGraph } from "./useWorkflowExecutionGraph.js";
import { useFollowExecution, computeFollowSelection } from "./useFollowExecution.js";
import { useActiveTaskName } from "./useActiveTaskName.js";
import { useExecutionAnnouncements } from "./useExecutionAnnouncements.js";
import { ExecutionActiveTaskIndicator } from "./ExecutionActiveTaskIndicator.js";
import { getAnimationDuration } from "../internal/motion-preference.js";
const nodeTypes = {
    [CANVAS_TASK_NODE_TYPE]: WorkflowNode,
};
const edgeTypes = {
    [CANVAS_TRANSITION_EDGE_TYPE]: CanvasTransitionEdge,
};
const defaultEdgeOptions = {
    markerEnd: { type: MarkerType.ArrowClosed, width: 16, height: 16 },
};
/**
 * Read-only execution graph canvas for workflow executions.
 *
 * Reuses the same `WorkflowNode` / `NodeShell` node rendering system from
 * the visual editor, wrapped in execution mode context to show live status
 * overlays instead of editing affordances.
 *
 * Designed for embedding in both the Stigmer Console and third-party
 * dashboards — no routing, auth, or app-shell dependencies (DD-004).
 *
 * @example
 * ```tsx
 * <WorkflowExecutionGraph
 *   executionId="wex_abc123"
 *   onTaskSelect={(name) => setInspectedTask(name)}
 * />
 * ```
 */
export const WorkflowExecutionGraph = memo(function WorkflowExecutionGraph(props) {
    return (_jsx(ReactFlowProvider, { children: _jsx(WorkflowExecutionGraphInner, { ...props }) }));
});
const TERMINAL_EXECUTION_PHASES = new Set([3, 4, 5, 6]);
function WorkflowExecutionGraphInner({ executionId, onTaskSelect, followExecution = false, execution: externalExecution, taskStates: externalTaskStates, onAutoSelectTask, panelOffsetPx = 0, nodesDraggable: draggable = false, className, }) {
    const graphState = useWorkflowExecutionGraph({
        executionId,
        execution: externalExecution,
        taskStates: externalTaskStates,
        onAutoSelectTask,
        nodesDraggable: draggable,
    });
    const { nodes, edges, isLoading, error, selectedTaskName, setSelectedTaskName, versionMismatch, taskStates, executionPhase, } = graphState;
    const { fitView } = useReactFlow();
    const [didInitialFit, setDidInitialFit] = useState(false);
    const isInitializedRef = useRef(false);
    const didFitGuardRef = useRef(false);
    // ── Ephemeral drag positions ───────────────────────────────────────
    // Resets when the execution changes (navigating to a different run).
    const [dragPositions, setDragPositions] = useState({});
    useEffect(() => {
        setDragPositions({});
    }, [executionId]);
    const hasDragOverrides = draggable && Object.keys(dragPositions).length > 0;
    const handleNodesChange = useCallback((changes) => {
        if (!draggable)
            return;
        const posChanges = changes.filter((c) => c.type === "position" && "position" in c && c.position != null);
        if (posChanges.length === 0)
            return;
        setDragPositions((prev) => {
            const next = { ...prev };
            for (const c of posChanges) {
                next[c.id] = c.position;
            }
            return next;
        });
    }, [draggable]);
    const handleResetLayout = useCallback(() => {
        setDragPositions({});
    }, []);
    const performInitialFit = useCallback(() => {
        if (didFitGuardRef.current)
            return;
        didFitGuardRef.current = true;
        fitView({ padding: 0.15, duration: getAnimationDuration(300) });
        setDidInitialFit(true);
    }, [fitView]);
    // onInit fires when ReactFlow's container is measured and the
    // viewport is ready — replacing the fragile 50ms setTimeout.
    const handleInit = useCallback(() => {
        isInitializedRef.current = true;
        if (nodes.length > 0) {
            performInitialFit();
        }
    }, [nodes.length, performInitialFit]);
    // When nodes arrive after onInit (async data), fit once they're ready.
    useEffect(() => {
        if (isInitializedRef.current && nodes.length > 0) {
            performInitialFit();
        }
    }, [nodes.length, performInitialFit]);
    // Derive active task name stably from taskStates (not from nodes array — DD-010)
    const activeTaskInfo = useActiveTaskName(taskStates);
    const isTerminal = executionPhase != null && TERMINAL_EXECUTION_PHASES.has(executionPhase);
    // Follow-execution state machine
    const { isFollowing, enableFollow, disableFollow, handleMoveStart, } = useFollowExecution({
        enabled: followExecution,
        activeTaskName: activeTaskInfo?.taskName ?? null,
        nodes,
        didInitialFit,
        isTerminal,
        panelOffsetPx,
    });
    // ── Follow-selection: auto-select the active task while following ──
    // Couples node selection to the follow state machine so "Follow" means
    // viewport centering + node highlighting + inspector display.
    useEffect(() => {
        const taskToSelect = computeFollowSelection({
            isFollowing,
            activeTaskName: activeTaskInfo?.taskName ?? null,
            currentSelectedTask: selectedTaskName,
        });
        if (!taskToSelect)
            return;
        setSelectedTaskName(taskToSelect);
        onTaskSelect?.(taskToSelect);
    }, [isFollowing, activeTaskInfo?.taskName, selectedTaskName, setSelectedTaskName, onTaskSelect]);
    // Screen reader announcements for task state changes
    const announcement = useExecutionAnnouncements(taskStates);
    const handleNodeClick = useCallback((_event, node) => {
        const data = node.data;
        if (data.isSentinel)
            return;
        const name = data.taskName;
        const next = name === selectedTaskName ? null : name;
        setSelectedTaskName(next);
        onTaskSelect?.(next);
        if (isFollowing)
            disableFollow();
    }, [selectedTaskName, setSelectedTaskName, onTaskSelect, isFollowing, disableFollow]);
    const handlePaneClick = useCallback(() => {
        setSelectedTaskName(null);
        onTaskSelect?.(null);
        if (isFollowing)
            disableFollow();
    }, [setSelectedTaskName, onTaskSelect, isFollowing, disableFollow]);
    const onMoveStart = useCallback((event, viewport) => {
        handleMoveStart(event, viewport);
    }, [handleMoveStart]);
    // Mark selected node + apply drag position overrides
    const nodesWithSelection = useMemo(() => nodes.map((n) => {
        const selected = n.data.taskName === selectedTaskName;
        const pos = dragPositions[n.id];
        return pos
            ? { ...n, selected, position: pos }
            : selected !== n.selected
                ? { ...n, selected }
                : n;
    }), [nodes, selectedTaskName, dragPositions]);
    if (isLoading) {
        return (_jsx("div", { className: cn("flex h-full items-center justify-center", className), children: _jsx(GraphLoadingSkeleton, {}) }));
    }
    if (error) {
        return (_jsx("div", { className: cn("flex h-full flex-col items-center justify-center gap-2 px-6 text-center", className), children: _jsx("p", { className: "text-sm text-[var(--stgm-muted-foreground,#737373)]", children: error }) }));
    }
    if (nodes.length === 0) {
        return (_jsx("div", { className: cn("flex h-full items-center justify-center text-sm text-[var(--stgm-muted-foreground,#737373)]", className), children: "No graph available for this execution" }));
    }
    return (_jsx(WorkflowGraphModeProvider, { mode: "execution", children: _jsxs("div", { className: cn("relative h-full w-full", className), children: [versionMismatch && (_jsx("div", { className: "absolute left-3 right-3 top-3 z-50 rounded-md border border-[var(--stgm-warning,#f59e0b)]/30 bg-[var(--stgm-warning,#f59e0b)]/5 px-3 py-2 text-xs text-[var(--stgm-foreground,#1a1a2e)]", children: versionMismatch })), followExecution && activeTaskInfo && (_jsx(ExecutionActiveTaskIndicator, { activeTask: activeTaskInfo, isFollowing: isFollowing, onFollowToggle: isFollowing ? disableFollow : enableFollow, onJumpToTask: () => enableFollow() })), hasDragOverrides && (_jsx("button", { type: "button", onClick: handleResetLayout, className: cn("absolute left-3 z-50 rounded-full border border-[var(--stgm-border,#e5e5e5)] bg-[var(--stgm-background,#fff)] px-3 py-1 text-xs text-[var(--stgm-foreground,#1a1a2e)] shadow-sm transition-colors hover:bg-[var(--stgm-muted,#f5f5f5)]", versionMismatch ? "top-12" : "top-3"), children: "Reset layout" })), _jsxs(ReactFlow, { nodes: nodesWithSelection, edges: edges, nodeTypes: nodeTypes, edgeTypes: edgeTypes, defaultEdgeOptions: defaultEdgeOptions, onInit: handleInit, onNodeClick: handleNodeClick, onPaneClick: handlePaneClick, onMoveStart: onMoveStart, onNodesChange: draggable ? handleNodesChange : undefined, nodesDraggable: draggable, nodesConnectable: false, nodesFocusable: true, elementsSelectable: true, panOnDrag: true, zoomOnScroll: true, fitView: false, minZoom: 0.2, maxZoom: 2, proOptions: { hideAttribution: true }, "aria-label": "Workflow execution graph. Use Tab to navigate between tasks.", children: [_jsx(Background, { variant: BackgroundVariant.Dots, gap: 16, size: 1 }), _jsx(Controls, { showInteractive: false }), _jsx(MiniMap, { nodeColor: (node) => {
                                const data = node.data;
                                const status = data.executionState?.status;
                                if (status === "completed")
                                    return "var(--stgm-success, #22c55e)";
                                if (status === "failed")
                                    return "var(--stgm-destructive, #ef4444)";
                                if (status === "running")
                                    return "var(--stgm-primary, #6366f1)";
                                return "var(--stgm-muted, #e5e5e5)";
                            }, pannable: true, zoomable: true })] }), _jsx("div", { role: "log", "aria-live": "polite", "aria-atomic": "false", className: "sr-only", children: announcement })] }) }));
}
function GraphLoadingSkeleton() {
    return (_jsxs("div", { className: "flex flex-col items-center gap-3", children: [_jsx("div", { className: "h-8 w-8 animate-pulse rounded-full bg-[var(--stgm-muted,#e5e5e5)]" }), _jsx("div", { className: "h-3 w-24 animate-pulse rounded bg-[var(--stgm-muted,#e5e5e5)]" }), _jsxs("div", { className: "mt-2 flex gap-4", children: [_jsx("div", { className: "h-10 w-32 animate-pulse rounded-md bg-[var(--stgm-muted,#e5e5e5)]" }), _jsx("div", { className: "h-10 w-32 animate-pulse rounded-md bg-[var(--stgm-muted,#e5e5e5)]" })] })] }));
}
//# sourceMappingURL=WorkflowExecutionGraph.js.map