/**
 * @license
 * Copyright 2026 HopCode Team Team
 * SPDX-License-Identifier: Apache-2.0
 */
/**
 * @fileoverview useArenaInProcess — bridges ArenaManager in-process events
 * to AgentViewContext agent registration.
 *
 * Subscribes to `config.onArenaManagerChange()` to react immediately when
 * the arena manager is set or cleared. Event listeners are attached to the
 * manager's emitter as soon as it appears — the backend is resolved lazily
 * inside the AGENT_START handler, which only fires after the backend is
 * initialized.
 */
import { useEffect, useRef } from 'react';
import { ArenaEventType, ArenaSessionStatus, DISPLAY_MODE, } from '@hoptrendy/hopcode-core';
import { theme } from '../semantic-colors.js';
const AGENT_COLORS = [
    theme.text.accent,
    theme.text.link,
    theme.status.success,
    theme.status.warning,
    theme.text.code,
    theme.status.error,
];
/**
 * Bridge arena in-process events to agent tab registration/unregistration.
 *
 * Called by AgentViewProvider — accepts config and actions directly so the
 * hook has no dependency on AgentViewContext (avoiding a circular import).
 */
export function useArenaInProcess(config, actions) {
    const actionsRef = useRef(actions);
    actionsRef.current = actions;
    useEffect(() => {
        if (!config)
            return;
        let detachArenaListeners = null;
        const retryTimeouts = new Set();
        /** Remove agent tabs, cancel pending retries, and detach arena events. */
        const detachSession = () => {
            actionsRef.current.unregisterAll();
            for (const t of retryTimeouts)
                clearTimeout(t);
            retryTimeouts.clear();
            detachArenaListeners?.();
            detachArenaListeners = null;
        };
        /** Attach to an arena manager's event emitter. The backend is resolved
         *  lazily — we only need it when registering agents, not at subscribe
         *  time. This avoids the race where setArenaManager fires before
         *  manager.start() initializes the backend. */
        const attachSession = (manager) => {
            const emitter = manager.getEventEmitter();
            let colorIndex = 0;
            const nextColor = () => AGENT_COLORS[colorIndex++ % AGENT_COLORS.length];
            /** Resolve the InProcessBackend, or null if not applicable. */
            const getInProcessBackend = () => {
                const backend = manager.getBackend();
                if (!backend || backend.type !== DISPLAY_MODE.IN_PROCESS)
                    return null;
                return backend;
            };
            // Register agents that already started (events may have fired before
            // the callback was attached).
            const inProcessBackend = getInProcessBackend();
            if (inProcessBackend) {
                for (const agentState of manager.getAgentStates()) {
                    const interactive = inProcessBackend.getAgent(agentState.agentId);
                    if (interactive) {
                        actionsRef.current.registerAgent(agentState.agentId, interactive, agentState.model.modelId, nextColor(), agentState.model.displayName);
                    }
                }
            }
            // AGENT_START fires *before* backend.spawnAgent() creates the
            // AgentInteractive, so getAgent() may return undefined. Retry briefly.
            const MAX_RETRIES = 20;
            const RETRY_MS = 50;
            const onAgentStart = (event) => {
                const tryRegister = (retriesLeft) => {
                    const backend = getInProcessBackend();
                    if (!backend)
                        return; // not an in-process session
                    const interactive = backend.getAgent(event.agentId);
                    if (interactive) {
                        actionsRef.current.registerAgent(event.agentId, interactive, event.model.modelId, nextColor(), event.model.displayName);
                        return;
                    }
                    if (retriesLeft > 0) {
                        const timeout = setTimeout(() => {
                            retryTimeouts.delete(timeout);
                            tryRegister(retriesLeft - 1);
                        }, RETRY_MS);
                        retryTimeouts.add(timeout);
                    }
                };
                tryRegister(MAX_RETRIES);
            };
            const onSessionComplete = (event) => {
                // IDLE means agents finished but the session is still alive for
                // follow-up interaction — keep the tab bar.
                if (event.result.status === ArenaSessionStatus.IDLE)
                    return;
                detachSession();
            };
            const onSessionError = () => detachSession();
            emitter.on(ArenaEventType.AGENT_START, onAgentStart);
            emitter.on(ArenaEventType.SESSION_COMPLETE, onSessionComplete);
            emitter.on(ArenaEventType.SESSION_ERROR, onSessionError);
            detachArenaListeners = () => {
                emitter.off(ArenaEventType.AGENT_START, onAgentStart);
                emitter.off(ArenaEventType.SESSION_COMPLETE, onSessionComplete);
                emitter.off(ArenaEventType.SESSION_ERROR, onSessionError);
            };
        };
        const handleManagerChange = (manager) => {
            detachSession();
            if (manager) {
                attachSession(manager);
            }
        };
        // Subscribe to future changes.
        config.onArenaManagerChange(handleManagerChange);
        // Handle the case where a manager already exists when we mount.
        const current = config.getArenaManager();
        if (current) {
            attachSession(current);
        }
        return () => {
            config.onArenaManagerChange(null);
            detachSession();
        };
    }, [config]);
}
//# sourceMappingURL=useArenaInProcess.js.map