import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
/**
 * @license
 * Copyright 2025 HopCode Team
 * SPDX-License-Identifier: Apache-2.0
 */
import { describe, it, expect, vi } from 'vitest';
import { render } from 'ink-testing-library';
import { Text } from 'ink';
import { Composer } from './Composer.js';
import { UIStateContext } from '../contexts/UIStateContext.js';
import { UIActionsContext, } from '../contexts/UIActionsContext.js';
import { ConfigContext } from '../contexts/ConfigContext.js';
// Mock VimModeContext hook
vi.mock('../contexts/VimModeContext.js', () => ({
    useVimMode: vi.fn(() => ({
        vimEnabled: false,
        vimMode: 'NORMAL',
    })),
}));
import { ApprovalMode } from '@hoptrendy/hopcode-core';
import { StreamingState } from '../types.js';
// Mock child components
vi.mock('./LoadingIndicator.js', () => ({
    LoadingIndicator: ({ thought }) => (_jsxs(Text, { children: ["LoadingIndicator", thought ? `: ${thought}` : ''] })),
}));
vi.mock('./ContextSummaryDisplay.js', () => ({
    ContextSummaryDisplay: () => _jsx(Text, { children: "ContextSummaryDisplay" }),
}));
vi.mock('./AutoAcceptIndicator.js', () => ({
    AutoAcceptIndicator: () => _jsx(Text, { children: "AutoAcceptIndicator" }),
}));
vi.mock('./ShellModeIndicator.js', () => ({
    ShellModeIndicator: () => _jsx(Text, { children: "ShellModeIndicator" }),
}));
vi.mock('./InputPrompt.js', () => ({
    InputPrompt: () => _jsx(Text, { children: "InputPrompt" }),
    calculatePromptWidths: vi.fn(() => ({
        inputWidth: 80,
        suggestionsWidth: 40,
        containerWidth: 84,
    })),
}));
vi.mock('./Footer.js', () => ({
    Footer: () => _jsx(Text, { children: "Footer" }),
}));
vi.mock('./QueuedMessageDisplay.js', () => ({
    QueuedMessageDisplay: ({ messageQueue }) => {
        if (messageQueue.length === 0) {
            return null;
        }
        return (_jsx(_Fragment, { children: messageQueue.map((message, index) => (_jsx(Text, { children: message }, index))) }));
    },
}));
// Mock contexts
vi.mock('../contexts/OverflowContext.js', () => ({
    OverflowProvider: ({ children }) => children,
}));
// Create mock context providers
const createMockUIState = (overrides = {}) => ({
    streamingState: null,
    contextFileNames: [],
    showAutoAcceptIndicator: ApprovalMode.DEFAULT,
    messageQueue: [],
    constrainHeight: false,
    isInputActive: true,
    buffer: '',
    inputWidth: 80,
    suggestionsWidth: 40,
    userMessages: [],
    slashCommands: [],
    commandContext: null,
    shellModeActive: false,
    isFocused: true,
    thought: '',
    currentLoadingPhrase: '',
    elapsedTime: 0,
    ctrlCPressedOnce: false,
    ctrlDPressedOnce: false,
    showEscapePrompt: false,
    ideContextState: null,
    contextMdFileCount: 0,
    showToolDescriptions: false,
    sessionStats: {
        lastPromptTokenCount: 0,
        sessionTokenCount: 0,
        totalPrompts: 0,
    },
    branchName: 'main',
    debugMessage: '',
    nightly: false,
    isTrustedFolder: true,
    taskStartTokens: 0,
    streamingResponseLengthRef: { current: 0 },
    isReceivingContent: false,
    pendingGeminiHistoryItems: [],
    terminalWidth: 80,
    ...overrides,
});
const createMockUIActions = () => ({
    handleFinalSubmit: vi.fn(),
    handleRetryLastPrompt: vi.fn(),
    handleClearScreen: vi.fn(),
    setShellModeActive: vi.fn(),
    onEscapePromptChange: vi.fn(),
    vimHandleInput: vi.fn(),
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
});
const createMockConfig = (overrides = {}) => ({
    getModel: vi.fn(() => 'gemini-1.5-pro'),
    getTargetDir: vi.fn(() => '/test/dir'),
    getDebugMode: vi.fn(() => false),
    getAccessibility: vi.fn(() => ({})),
    getMcpServers: vi.fn(() => ({})),
    getBlockedMcpServers: vi.fn(() => []),
    ...overrides,
});
/* eslint-disable @typescript-eslint/no-explicit-any */
const renderComposer = (uiState, config = createMockConfig(), uiActions = createMockUIActions()) => render(_jsx(ConfigContext.Provider, { value: config, children: _jsx(UIStateContext.Provider, { value: uiState, children: _jsx(UIActionsContext.Provider, { value: uiActions, children: _jsx(Composer, {}) }) }) }));
/* eslint-enable @typescript-eslint/no-explicit-any */
describe('Composer', () => {
    describe('Footer Display', () => {
        it('renders Footer by default', () => {
            const uiState = createMockUIState();
            const { lastFrame } = renderComposer(uiState);
            // Smoke check that the Footer renders
            expect(lastFrame()).toContain('Footer');
        });
    });
    describe('Loading Indicator', () => {
        it('renders LoadingIndicator with thought when streaming', () => {
            const uiState = createMockUIState({
                streamingState: StreamingState.Responding,
                thought: {
                    subject: 'Processing',
                    description: 'Processing your request...',
                },
                currentLoadingPhrase: 'Analyzing',
                elapsedTime: 1500,
            });
            const { lastFrame } = renderComposer(uiState);
            const output = lastFrame();
            expect(output).toContain('LoadingIndicator');
        });
        it('renders LoadingIndicator without thought when accessibility disables loading phrases', () => {
            const uiState = createMockUIState({
                streamingState: StreamingState.Responding,
                thought: { subject: 'Hidden', description: 'Should not show' },
            });
            const config = createMockConfig({
                getAccessibility: vi.fn(() => ({ disableLoadingPhrases: true })),
            });
            const { lastFrame } = renderComposer(uiState, config);
            const output = lastFrame();
            expect(output).toContain('LoadingIndicator');
            expect(output).not.toContain('Should not show');
        });
        // ─── Narrow-terminal suppression (suppressBottomLoadingIndicator) ───
        // The indicator is hidden only when actively Responding on a terminal
        // ≤ 30 cols wide. WaitingForConfirmation must NEVER be suppressed.
        it('hides LoadingIndicator when Responding on a 30-col terminal', () => {
            const uiState = createMockUIState({
                streamingState: StreamingState.Responding,
                terminalWidth: 30,
            });
            const { lastFrame } = renderComposer(uiState);
            expect(lastFrame()).not.toContain('LoadingIndicator');
        });
        it('hides LoadingIndicator when Responding on a 25-col terminal', () => {
            const uiState = createMockUIState({
                streamingState: StreamingState.Responding,
                terminalWidth: 25,
            });
            const { lastFrame } = renderComposer(uiState);
            expect(lastFrame()).not.toContain('LoadingIndicator');
        });
        it('preserves "esc to cancel" fallback when LoadingIndicator is suppressed', () => {
            // Even when the full LoadingIndicator is hidden on ultra-narrow
            // terminals, the cancel affordance must remain so users can abort.
            const uiState = createMockUIState({
                streamingState: StreamingState.Responding,
                terminalWidth: 25,
            });
            const { lastFrame } = renderComposer(uiState);
            const output = lastFrame();
            expect(output).not.toContain('LoadingIndicator');
            expect(output).toContain('Esc to cancel');
        });
        it('does not render the esc fallback once the full indicator is visible', () => {
            const uiState = createMockUIState({
                streamingState: StreamingState.Responding,
                terminalWidth: 31,
            });
            const { lastFrame } = renderComposer(uiState);
            const output = lastFrame();
            expect(output).toContain('LoadingIndicator');
            // The minimal fallback string only appears when the full indicator is
            // suppressed — when LoadingIndicator renders, it owns the cancel hint.
            expect(output).not.toContain('Esc to cancel');
        });
        it('shows LoadingIndicator when Responding on a 31-col terminal', () => {
            const uiState = createMockUIState({
                streamingState: StreamingState.Responding,
                terminalWidth: 31,
            });
            const { lastFrame } = renderComposer(uiState);
            expect(lastFrame()).toContain('LoadingIndicator');
        });
        it('shows LoadingIndicator when WaitingForConfirmation even on a 25-col terminal', () => {
            // Confirmation prompts must remain visible regardless of width — the
            // user needs to see something is awaiting their input.
            const uiState = createMockUIState({
                streamingState: StreamingState.WaitingForConfirmation,
                terminalWidth: 25,
            });
            const { lastFrame } = renderComposer(uiState);
            expect(lastFrame()).toContain('LoadingIndicator');
        });
        it('suppresses thought when waiting for confirmation', () => {
            const uiState = createMockUIState({
                streamingState: StreamingState.WaitingForConfirmation,
                thought: {
                    subject: 'Confirmation',
                    description: 'Should not show during confirmation',
                },
            });
            const { lastFrame } = renderComposer(uiState);
            const output = lastFrame();
            expect(output).toContain('LoadingIndicator');
            expect(output).not.toContain('Should not show during confirmation');
        });
    });
    describe('Message Queue Display', () => {
        it('displays queued messages when present', () => {
            const uiState = createMockUIState({
                messageQueue: [
                    'First queued message',
                    'Second queued message',
                    'Third queued message',
                ],
            });
            const { lastFrame } = renderComposer(uiState);
            const output = lastFrame();
            expect(output).toContain('First queued message');
            expect(output).toContain('Second queued message');
            expect(output).toContain('Third queued message');
        });
        it('renders QueuedMessageDisplay with empty message queue', () => {
            const uiState = createMockUIState({
                messageQueue: [],
            });
            const { lastFrame } = renderComposer(uiState);
            // The component should render but return null for empty queue
            // This test verifies that the component receives the correct prop
            const output = lastFrame();
            expect(output).toContain('InputPrompt'); // Verify basic Composer rendering
        });
    });
    describe('Context and Status Display', () => {
        // Note: ContextSummaryDisplay and status prompts are now rendered in Footer, not Composer
        it('shows empty space in normal state (ContextSummaryDisplay moved to Footer)', () => {
            const uiState = createMockUIState({
                ctrlCPressedOnce: false,
                ctrlDPressedOnce: false,
                showEscapePrompt: false,
            });
            const { lastFrame } = renderComposer(uiState);
            // ContextSummaryDisplay is now in Footer, so we just verify normal state renders
            expect(lastFrame()).toBeDefined();
        });
        // Note: Ctrl+C, Ctrl+D, and Escape prompts are now rendered in Footer component
        // These are tested in Footer.test.tsx
        it('renders Footer which handles Ctrl+C exit prompt', () => {
            const uiState = createMockUIState({
                ctrlCPressedOnce: true,
            });
            const { lastFrame } = renderComposer(uiState);
            // Ctrl+C prompt is now inside Footer, verify Footer renders
            expect(lastFrame()).toContain('Footer');
        });
        it('renders Footer which handles Ctrl+D exit prompt', () => {
            const uiState = createMockUIState({
                ctrlDPressedOnce: true,
            });
            const { lastFrame } = renderComposer(uiState);
            // Ctrl+D prompt is now inside Footer, verify Footer renders
            expect(lastFrame()).toContain('Footer');
        });
        it('renders Footer which handles escape prompt', () => {
            const uiState = createMockUIState({
                showEscapePrompt: true,
            });
            const { lastFrame } = renderComposer(uiState);
            // Escape prompt is now inside Footer, verify Footer renders
            expect(lastFrame()).toContain('Footer');
        });
    });
    describe('Input and Indicators', () => {
        it('renders InputPrompt when input is active', () => {
            const uiState = createMockUIState({
                isInputActive: true,
            });
            const { lastFrame } = renderComposer(uiState);
            expect(lastFrame()).toContain('InputPrompt');
        });
        it('does not render InputPrompt when input is inactive', () => {
            const uiState = createMockUIState({
                isInputActive: false,
            });
            const { lastFrame } = renderComposer(uiState);
            expect(lastFrame()).not.toContain('InputPrompt');
        });
        // Note: AutoAcceptIndicator and ShellModeIndicator are now rendered inside Footer component
        // These are tested in Footer.test.tsx
        it('renders Footer which contains AutoAcceptIndicator when approval mode is not default', () => {
            const uiState = createMockUIState({
                showAutoAcceptIndicator: ApprovalMode.IZN,
                shellModeActive: false,
            });
            const { lastFrame } = renderComposer(uiState);
            // AutoAcceptIndicator is now inside Footer, verify Footer renders
            expect(lastFrame()).toContain('Footer');
        });
        it('renders Footer which contains ShellModeIndicator when shell mode is active', () => {
            const uiState = createMockUIState({
                shellModeActive: true,
            });
            const { lastFrame } = renderComposer(uiState);
            // ShellModeIndicator is now inside Footer, verify Footer renders
            expect(lastFrame()).toContain('Footer');
        });
    });
});
//# sourceMappingURL=Composer.test.js.map