import { useCallback } from "react";
import { parseAgentRunStatusData } from "../../services/agentStatus";
import { toUserFacingAgentErrorMessage } from "../../services/agentErrorMessage";
import { MACHINE_CAPACITY_REASON } from "../agentMessageHelpers";
import { applyToolApprovalsRequiredToTranscript, completeOpenStreamingMessagesInTranscript, } from "./agentSessionState";
import { hasNonZeroLiveTotals, liveTotalsFromStatusTotals, } from "./agentSessionLiveTotals";
import { markStaleRunningLoadSuppressed } from "./useAgentSessionSync";
import { isBrowserCaptureDialogType } from "./useAgentBrowserCapture";
export function useAgentRunStatusSocketHandler(input) {
    const { agent, agentStubId, actions, currentRunIdRef, isStoppingRef, isWaitingRef, messagesRef, shouldCreateNewMessageRef, lastNonHeartbeatUpdateAtRef, reconcileServerStateRef, normalizeRunId, noteMissingRunId, appendToolUiEvent, acceptRunSequenceFrame, clearStopGuard, clearHeartbeatMessages, clearPendingBrowserCaptureWait, setPendingBrowserCaptureWait, schedulePendingDialogReplay, settleCompletedRun, setAgent, setAgentMetadata, setError, setLastRunStatusReason, setIsConnecting, setIsWaitingForResponse, setIsAgentThinking, } = input;
    return useCallback((messageType, payload) => {
        if (messageType !== "agent:run:status") {
            return false;
        }
        const agentId = payload?.agentId;
        // Drop stale-run status — see matching block in agent:run:delta handler.
        const statusRunId = normalizeRunId(payload?.runId);
        if (statusRunId === null) {
            noteMissingRunId("agent:run:status");
        }
        else if (currentRunIdRef.current !== null &&
            statusRunId !== currentRunIdRef.current) {
            appendToolUiEvent("ui:stream-runid-dropped", `agent:run:status runId=${statusRunId} currentRunId=${currentRunIdRef.current}`);
            return true;
        }
        const { seq, data: statusData } = payload;
        if (!acceptRunSequenceFrame({
            eventName: "agent:run:status",
            runId: payload?.runId,
            seq,
        })) {
            return true;
        }
        // Status events never carry a "Heartbeat" payload — heartbeats are deltas. Any
        // status update is meaningful progress for the watchdog.
        lastNonHeartbeatUpdateAtRef.current = Date.now();
        // Route based on statusData.state
        try {
            // Normalize various status shapes and handle Cancelled uniformly
            const normalizedStatus = parseAgentRunStatusData(statusData);
            const statusReason = typeof statusData?.reason === "string"
                ? statusData.reason.trim() || null
                : null;
            const statusMessage = typeof statusData?.message === "string"
                ? statusData.message.trim() || null
                : null;
            if (normalizedStatus === "idle") {
                const wasStopping = isStoppingRef.current;
                if (wasStopping) {
                    markStaleRunningLoadSuppressed(agentStubId);
                }
                clearStopGuard();
                actions.clearStopGuard();
                actions.runStatus("idle", statusReason);
                setError(null);
                // Stop indicators and mark any in-progress streaming messages as completed
                clearHeartbeatMessages();
                setAgent((prev) => (prev ? { ...prev, status: "idle" } : prev));
                isWaitingRef.current = false;
                shouldCreateNewMessageRef.current = false;
                actions.patchRunState({
                    isAgentThinking: false,
                    isConnecting: false,
                    isSubmitting: false,
                    isWaitingForResponse: false,
                    lastStatusReason: null,
                });
                messagesRef.current = completeOpenStreamingMessagesInTranscript(messagesRef.current);
                actions.completeOpenStreamingMessages();
                if (wasStopping) {
                    return true;
                }
                void reconcileServerStateRef.current?.();
                return true;
            }
            if (statusData?.state === "streamOpen") {
                setIsConnecting(false);
                return true;
            }
            if (statusData?.state === "tokenUsage") {
                const totals = statusData?.totals;
                if (totals) {
                    const totalCost = Number(totals.totalCost) || 0;
                    const statusCostLimit = (() => {
                        try {
                            const v = statusData?.costLimit;
                            const n = v != null ? Number(v) : undefined;
                            return Number.isFinite(n) && n > 0
                                ? n
                                : undefined;
                        }
                        catch {
                            return undefined;
                        }
                    })();
                    const nextTotals = liveTotalsFromStatusTotals(totals);
                    if (nextTotals && hasNonZeroLiveTotals(nextTotals)) {
                        actions.replaceLiveTotals(nextTotals);
                    }
                    // Fallback context usage update for providers that do not include
                    // context usage in every stream delta (for example some OpenAI streams).
                    // Prefer explicit status values when present; otherwise derive from totals.
                    const contextWindowValue = Number(statusData?.contextWindow ??
                        agent?.contextWindowTokens ??
                        0);
                    const contextUsedValue = Number(statusData?.contextUsed ??
                        (Number(totals.totalInputTokens) || 0) +
                            (Number(totals.totalCachedInputTokens) || 0) +
                            (Number(totals.totalCacheWriteTokens) || 0));
                    if (contextWindowValue > 0 &&
                        Number.isFinite(contextUsedValue) &&
                        contextUsedValue >= 0) {
                        actions.replaceContextWindowStatus({
                            contextWindowTokens: contextWindowValue,
                            estimatedInputTokens: contextUsedValue,
                            contextUsedPercent: (contextUsedValue / contextWindowValue) * 100,
                            model: agent?.model || "",
                        });
                    }
                    // If server provides costLimit along with totals, persist it locally
                    if (statusCostLimit) {
                        setAgent((prev) => prev && (!prev.costLimit || prev.costLimit !== statusCostLimit)
                            ? { ...prev, costLimit: statusCostLimit }
                            : prev);
                    }
                    if (agent?.costLimit && totalCost > agent.costLimit) {
                        actions.replaceCostLimitExceeded({
                            totalCost: totalCost,
                            costLimit: agent.costLimit,
                            initialCostLimit: agent.costLimit,
                        });
                        setIsWaitingForResponse(false);
                        shouldCreateNewMessageRef.current = false;
                    }
                }
                return true;
            }
            if (statusData?.state === "ToolApprovalsRequired" ||
                statusData?.state === "toolApprovalsRequired") {
                clearPendingBrowserCaptureWait();
                setLastRunStatusReason(null);
                const msgId = statusData.messageId;
                const ids = statusData.toolCallIds || [];
                if (msgId && Array.isArray(ids) && ids.length > 0) {
                    messagesRef.current = applyToolApprovalsRequiredToTranscript(messagesRef.current, {
                        messageId: msgId,
                        toolCallIds: ids,
                    });
                    actions.toolApprovalsRequired({
                        messageId: msgId,
                        toolCallIds: ids,
                    });
                }
                else {
                    actions.runStatus("waitingForApproval");
                }
                // Update agent status to waiting for approval
                setAgent((prev) => prev ? { ...prev, status: "waitingForApproval" } : prev);
                setIsConnecting(false);
                setIsWaitingForResponse(false);
                return true;
            }
            // Handle waiting states explicitly
            if (normalizedStatus === "waitingForApproval") {
                clearStopGuard();
                actions.clearStopGuard();
                actions.runStatus("waitingForApproval", statusReason);
                setLastRunStatusReason(null);
                setError(null);
                clearPendingBrowserCaptureWait();
                setAgent((prev) => prev ? { ...prev, status: "waitingForApproval" } : prev);
                setIsConnecting(false);
                setIsWaitingForResponse(false);
                setIsAgentThinking(false);
                void reconcileServerStateRef.current?.();
                return true;
            }
            if (normalizedStatus === "waitingForInput") {
                clearStopGuard();
                actions.clearStopGuard();
                actions.runStatus("waitingForInput", statusReason);
                setLastRunStatusReason(null);
                setError(null);
                const dialogType = typeof statusData?.dialogType === "string"
                    ? statusData.dialogType
                    : null;
                const callbackId = typeof statusData?.callbackId === "string" &&
                    statusData.callbackId.trim()
                    ? statusData.callbackId.trim()
                    : null;
                const isBrowserCaptureWait = isBrowserCaptureDialogType(dialogType);
                if (callbackId && !isBrowserCaptureWait) {
                    schedulePendingDialogReplay(agentId, callbackId, dialogType);
                }
                const captureCallbackId = isBrowserCaptureWait && callbackId ? callbackId : null;
                setPendingBrowserCaptureWait(isBrowserCaptureWait ? dialogType : null, captureCallbackId);
                setAgent((prev) => prev
                    ? {
                        ...prev,
                        status: "waitingForInput",
                        statusMessage: isBrowserCaptureWait &&
                            typeof statusData?.title === "string" &&
                            statusData.title.trim()
                            ? statusData.title.trim()
                            : prev.statusMessage,
                    }
                    : prev);
                setIsConnecting(false);
                setIsWaitingForResponse(false);
                setIsAgentThinking(false);
                return true;
            }
            if (normalizedStatus === "costLimitReached") {
                clearStopGuard();
                actions.clearStopGuard();
                actions.runStatus("costLimitReached", statusReason);
                setError(null);
                clearPendingBrowserCaptureWait();
                const totalCost = Number(statusData.totalCost) || 0;
                const costLimit = Number(statusData.costLimit) || agent?.costLimit || 0;
                actions.replaceCostLimitExceeded({
                    totalCost: totalCost,
                    costLimit: costLimit,
                    initialCostLimit: costLimit,
                });
                // Update agent status to cost limit reached
                setAgent((prev) => prev ? { ...prev, status: "costLimitReached" } : prev);
                setIsWaitingForResponse(false);
                setIsConnecting(false);
                return true;
            }
            if (statusData?.state === "contextChanged") {
                // Server sends additionalData directly (with todoList inside)
                // Also may include ChildAgents for spawned agents
                try {
                    const serverAdditionalData = statusData.additionalData || {};
                    setAgentMetadata((prev) => {
                        const current = (prev || {});
                        const updated = { ...current };
                        // Merge additionalData (deep merge to preserve existing values)
                        if (serverAdditionalData &&
                            Object.keys(serverAdditionalData).length > 0) {
                            updated.additionalData = {
                                ...(current.additionalData || {}),
                                ...serverAdditionalData,
                            };
                        }
                        // Merge ChildAgents if present (for spawned agents) - replace entire array
                        // Backend sends the complete updated list, not just additions
                        if (statusData.childAgents) {
                            const childAgents = statusData.childAgents;
                            if (Array.isArray(childAgents)) {
                                updated.childAgents = childAgents;
                            }
                        }
                        return updated;
                    });
                }
                catch (err) {
                    console.error("[AgentTerminal] Error handling contextChanged:", err);
                }
                return true;
            }
            // Handle "completed" state (fallback for legacy code paths that send status instead of lifecycle event)
            if (normalizedStatus === "completed") {
                // Pass through the runId from the status payload so the
                // run-scoped idempotency guard in settleCompletedRun can drop
                // duplicates of agent:run:complete that already settled this run.
                settleCompletedRun("completed", payload?.runId);
                actions.settleRun({
                    finalStatus: "completed",
                    runId: payload?.runId,
                });
                return true;
            }
            // Handle "Running" state - agent is actively processing
            if (normalizedStatus === "running") {
                if (isStoppingRef.current) {
                    return true;
                }
                if (statusReason === MACHINE_CAPACITY_REASON) {
                    clearHeartbeatMessages();
                    setLastRunStatusReason(statusReason);
                    setAgent((prev) => prev
                        ? {
                            ...prev,
                            status: "running",
                            statusMessage: statusMessage ||
                                "Waiting for capacity. The agent will start automatically when a slot becomes available.",
                        }
                        : prev);
                    setIsWaitingForResponse(false);
                    isWaitingRef.current = false;
                    setIsConnecting(false);
                    setIsAgentThinking(false);
                    return true;
                }
                setLastRunStatusReason(null);
                setError(null);
                actions.runStatus("running", statusReason);
                // Update agent status to running and clear any previous error statusMessage
                setAgent((prev) => prev
                    ? { ...prev, status: "running", statusMessage: undefined }
                    : prev);
                setIsWaitingForResponse(true);
                isWaitingRef.current = true;
                setIsAgentThinking(true);
                return true;
            }
            // Handle "Error" state
            if (normalizedStatus === "error") {
                clearStopGuard();
                actions.clearStopGuard();
                actions.runStatus("error", statusReason);
                setLastRunStatusReason(null);
                const errorMsg = toUserFacingAgentErrorMessage(statusData?.statusMessage ??
                    statusData?.message ??
                    statusData?.error) || "Unknown error";
                clearHeartbeatMessages();
                setError(errorMsg);
                setAgent((prev) => prev ? { ...prev, status: "error", statusMessage: errorMsg } : prev);
                setIsWaitingForResponse(false);
                isWaitingRef.current = false;
                setIsConnecting(false);
                setIsAgentThinking(false);
                return true;
            }
        }
        catch (err) {
            console.error("[AgentTerminal] Error handling status update:", err);
        }
        return true;
    }, [
        acceptRunSequenceFrame,
        actions,
        agent,
        agentStubId,
        appendToolUiEvent,
        clearHeartbeatMessages,
        clearPendingBrowserCaptureWait,
        clearStopGuard,
        currentRunIdRef,
        isStoppingRef,
        isWaitingRef,
        lastNonHeartbeatUpdateAtRef,
        messagesRef,
        normalizeRunId,
        noteMissingRunId,
        reconcileServerStateRef,
        schedulePendingDialogReplay,
        setAgent,
        setAgentMetadata,
        setError,
        setIsAgentThinking,
        setIsConnecting,
        setIsWaitingForResponse,
        setLastRunStatusReason,
        setPendingBrowserCaptureWait,
        settleCompletedRun,
        shouldCreateNewMessageRef,
    ]);
}
//# sourceMappingURL=useAgentRunStatusSocketHandler.js.map