import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
/**
 * @license
 * Copyright 2026 HopCode Team Team
 * SPDX-License-Identifier: Apache-2.0
 */
/**
 * @fileoverview AgentComposer — footer area for in-process agent tabs.
 *
 * Replaces the main Composer when an agent tab is active so that:
 *  - The loading indicator reflects the agent's status (not the main agent)
 *  - The input prompt sends messages to the agent (via enqueueMessage)
 *  - Keyboard events are scoped — no conflict with the main InputPrompt
 *
 * Wraps its content in a local StreamingContext.Provider so reusable
 * components like LoadingIndicator and HopCodeRespondingSpinner read the
 * agent's derived streaming state instead of the main agent's.
 */
import { Box, Text, useStdin } from 'ink';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { AgentStatus, isTerminalStatus, ApprovalMode, APPROVAL_MODES, } from '@hoptrendy/hopcode-core';
import { useAgentViewState, useAgentViewActions, } from '../../contexts/AgentViewContext.js';
import { useConfig } from '../../contexts/ConfigContext.js';
import { StreamingContext } from '../../contexts/StreamingContext.js';
import { StreamingState } from '../../types.js';
import { useTerminalSize } from '../../hooks/useTerminalSize.js';
import { useAgentStreamingState } from '../../hooks/useAgentStreamingState.js';
import { useKeypress } from '../../hooks/useKeypress.js';
import { useTextBuffer } from '../shared/text-buffer.js';
import { calculatePromptWidths } from '../../utils/layoutUtils.js';
import { BaseTextInput } from '../BaseTextInput.js';
import { LoadingIndicator } from '../LoadingIndicator.js';
import { QueuedMessageDisplay } from '../QueuedMessageDisplay.js';
import { AgentFooter } from './AgentFooter.js';
import { keyMatchers, Command } from '../../keyMatchers.js';
import { theme } from '../../semantic-colors.js';
import { t } from '../../../i18n/index.js';
// ─── Component ──────────────────────────────────────────────
export const AgentComposer = ({ agentId }) => {
    const { agents, agentTabBarFocused, agentShellFocused, agentApprovalModes } = useAgentViewState();
    const { setAgentInputBufferText, setAgentTabBarFocused, setAgentApprovalMode, } = useAgentViewActions();
    const agent = agents.get(agentId);
    const interactiveAgent = agent?.interactiveAgent;
    const config = useConfig();
    const { columns: terminalWidth } = useTerminalSize();
    const { inputWidth } = calculatePromptWidths(terminalWidth);
    const { stdin, setRawMode } = useStdin();
    const { status, streamingState, isInputActive, elapsedTime, lastPromptTokenCount, } = useAgentStreamingState(interactiveAgent);
    // ── Escape to cancel the active agent round ──
    useKeypress((key) => {
        if (key.name === 'escape' &&
            streamingState === StreamingState.Responding) {
            interactiveAgent?.cancelCurrentRound();
        }
    }, {
        isActive: streamingState === StreamingState.Responding && !agentShellFocused,
    });
    // ── Shift+Tab to cycle this agent's approval mode ──
    const agentApprovalMode = agentApprovalModes.get(agentId) ?? ApprovalMode.DEFAULT;
    useKeypress((key) => {
        const isShiftTab = key.shift && key.name === 'tab';
        const isWindowsTab = process.platform === 'win32' &&
            key.name === 'tab' &&
            !key.ctrl &&
            !key.meta;
        if (isShiftTab || isWindowsTab) {
            const currentIndex = APPROVAL_MODES.indexOf(agentApprovalMode);
            const nextIndex = currentIndex === -1 ? 0 : (currentIndex + 1) % APPROVAL_MODES.length;
            setAgentApprovalMode(agentId, APPROVAL_MODES[nextIndex]);
        }
    }, { isActive: !agentShellFocused });
    // ── Input buffer (independent from main agent) ──
    const isValidPath = useCallback(() => false, []);
    const buffer = useTextBuffer({
        initialText: '',
        viewport: { height: 3, width: inputWidth },
        stdin,
        setRawMode,
        isValidPath,
    });
    // Sync agent buffer text to context so AgentTabBar can guard tab switching
    useEffect(() => {
        setAgentInputBufferText(buffer.text);
        return () => setAgentInputBufferText('');
    }, [buffer.text, setAgentInputBufferText]);
    // When agent input is not active (agent running, completed, etc.),
    // auto-focus the tab bar so arrow keys switch tabs directly.
    // We also depend on streamingState so that transitions like
    // WaitingForConfirmation → Responding re-trigger the effect — the
    // approval keypress releases tab-bar focus (printable char handler),
    // but isInputActive stays false throughout, so without this extra
    // dependency the focus would never be restored.
    useEffect(() => {
        if (!isInputActive) {
            setAgentTabBarFocused(true);
        }
    }, [isInputActive, streamingState, setAgentTabBarFocused]);
    // ── Focus management between input and tab bar ──
    const handleKeypress = useCallback((key) => {
        // When tab bar has focus, block all non-printable keys so they don't
        // act on the hidden buffer. Printable characters fall through to
        // BaseTextInput naturally; the tab bar handler releases focus on the
        // same event so the keystroke appears in the input immediately.
        if (agentTabBarFocused) {
            if (key.sequence &&
                key.sequence.length === 1 &&
                !key.ctrl &&
                !key.meta) {
                return false; // let BaseTextInput type the character
            }
            return true; // consume non-printable keys
        }
        // Down arrow at the bottom edge (or empty buffer) → focus the tab bar
        if (keyMatchers[Command.NAVIGATION_DOWN](key)) {
            if (buffer.text === '' ||
                buffer.allVisualLines.length === 1 ||
                buffer.visualCursor[0] === buffer.allVisualLines.length - 1) {
                setAgentTabBarFocused(true);
                return true;
            }
        }
        return false;
    }, [buffer, agentTabBarFocused, setAgentTabBarFocused]);
    // ── Message queue (accumulate while streaming, flush as one prompt on idle) ──
    const [messageQueue, setMessageQueue] = useState([]);
    // When agent becomes idle (and not terminal), flush queued messages.
    useEffect(() => {
        if (streamingState === StreamingState.Idle &&
            messageQueue.length > 0 &&
            status !== undefined &&
            !isTerminalStatus(status)) {
            const combined = messageQueue.join('\n');
            setMessageQueue([]);
            interactiveAgent?.enqueueMessage(combined);
        }
    }, [streamingState, messageQueue, interactiveAgent, status]);
    const handleSubmit = useCallback((text) => {
        const trimmed = text.trim();
        if (!trimmed || !interactiveAgent)
            return;
        if (streamingState === StreamingState.Idle) {
            interactiveAgent.enqueueMessage(trimmed);
        }
        else {
            setMessageQueue((prev) => [...prev, trimmed]);
        }
    }, [interactiveAgent, streamingState]);
    // ── Render ──
    const statusLabel = useMemo(() => {
        switch (status) {
            case AgentStatus.COMPLETED:
                return { text: t('Completed'), color: theme.status.success };
            case AgentStatus.FAILED:
                return {
                    text: t('Failed: {{error}}', {
                        error: interactiveAgent?.getError() ??
                            interactiveAgent?.getLastRoundError() ??
                            'unknown',
                    }),
                    color: theme.status.error,
                };
            case AgentStatus.CANCELLED:
                return { text: t('Cancelled'), color: theme.text.secondary };
            default:
                return null;
        }
    }, [status, interactiveAgent]);
    // ── Approval-mode styling (mirrors main InputPrompt) ──
    const isYolo = agentApprovalMode === ApprovalMode.YOLO;
    const isAutoAccept = agentApprovalMode !== ApprovalMode.DEFAULT;
    const statusColor = isYolo
        ? theme.status.errorDim
        : isAutoAccept
            ? theme.status.warningDim
            : undefined;
    const inputBorderColor = !isInputActive || agentTabBarFocused
        ? theme.border.default
        : (statusColor ?? theme.border.focused);
    const prefixNode = (_jsxs(Text, { color: statusColor ?? theme.text.accent, children: [isYolo ? '*' : '>', " "] }));
    return (_jsx(StreamingContext.Provider, { value: streamingState, children: _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(LoadingIndicator, { currentLoadingPhrase: streamingState === StreamingState.Responding
                        ? t('Thinking…')
                        : undefined, elapsedTime: elapsedTime }), statusLabel && (_jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: statusLabel.color, children: statusLabel.text }) })), _jsx(QueuedMessageDisplay, { messageQueue: messageQueue }), _jsx(BaseTextInput, { buffer: buffer, onSubmit: handleSubmit, onKeypress: handleKeypress, showCursor: isInputActive && !agentTabBarFocused, placeholder: '  ' + t('Send a message to this agent'), prefix: prefixNode, borderColor: inputBorderColor, isActive: isInputActive && !agentShellFocused }), _jsx(AgentFooter, { approvalMode: agentApprovalMode, promptTokenCount: lastPromptTokenCount, contextWindowSize: config.getContentGeneratorConfig()?.contextWindowSize, terminalWidth: terminalWidth })] }) }));
};
//# sourceMappingURL=AgentComposer.js.map