import { jsx as _jsx } from "react/jsx-runtime";
/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { renderWithProviders } from '../../../test-utils/render.js';
import { describe, it, expect, vi, afterEach } from 'vitest';
import { ToolGroupMessage } from './ToolGroupMessage.js';
import { ToolCallStatus } from '../../types.js';
import { ScrollableList, } from '../shared/ScrollableList.js';
import { Box, Text } from 'ink';
import { act, useRef, useEffect } from 'react';
import { waitFor } from '../../../test-utils/async.js';
import { SHELL_COMMAND_NAME } from '../../constants.js';
// Mock child components that might be complex
vi.mock('../TerminalOutput.js', () => ({
    TerminalOutput: () => _jsx(Text, { children: "MockTerminalOutput" }),
}));
vi.mock('../AnsiOutput.js', () => ({
    AnsiOutputText: () => _jsx(Text, { children: "MockAnsiOutput" }),
}));
vi.mock('../GeminiRespondingSpinner.js', () => ({
    GeminiRespondingSpinner: () => _jsx(Text, { children: "MockRespondingSpinner" }),
}));
vi.mock('./DiffRenderer.js', () => ({
    DiffRenderer: () => _jsx(Text, { children: "MockDiff" }),
}));
vi.mock('../../utils/MarkdownDisplay.js', () => ({
    MarkdownDisplay: ({ text }) => _jsx(Text, { children: text }),
}));
describe('ToolMessage Sticky Header Regression', () => {
    afterEach(() => {
        vi.restoreAllMocks();
    });
    const createToolCall = (id, name, resultPrefix) => ({
        callId: id,
        name,
        description: `Description for ${name}`,
        resultDisplay: Array.from({ length: 10 }, (_, i) => `${resultPrefix}-${String(i + 1).padStart(2, '0')}`).join('\n'),
        status: ToolCallStatus.Success,
        confirmationDetails: undefined,
        renderOutputAsMarkdown: false,
    });
    it('verifies that multiple ToolMessages in a ToolGroupMessage in a ScrollableList have sticky headers', async () => {
        const toolCalls = [
            createToolCall('1', 'tool-1', 'c1'),
            createToolCall('2', 'tool-2', 'c2'),
        ];
        const terminalWidth = 80;
        const terminalHeight = 5;
        let listRef = null;
        const TestComponent = () => {
            const internalRef = useRef(null);
            useEffect(() => {
                listRef = internalRef.current;
            }, []);
            return (_jsx(ScrollableList, { ref: internalRef, data: ['item1'], renderItem: () => (_jsx(ToolGroupMessage, { groupId: 1, toolCalls: toolCalls, terminalWidth: terminalWidth - 2 })), estimatedItemHeight: () => 30, keyExtractor: (item) => item, hasFocus: true }));
        };
        const { lastFrame } = renderWithProviders(_jsx(Box, { height: terminalHeight, children: _jsx(TestComponent, {}) }), {
            width: terminalWidth,
            uiState: { terminalWidth },
        });
        // Initial state: tool-1 should be visible
        await waitFor(() => {
            expect(lastFrame()).toContain('tool-1');
        });
        expect(lastFrame()).toContain('Description for tool-1');
        expect(lastFrame()).toMatchSnapshot();
        // Scroll down so that tool-1's header should be stuck
        await act(async () => {
            listRef?.scrollBy(5);
        });
        // tool-1 header should still be visible because it is sticky
        await waitFor(() => {
            expect(lastFrame()).toContain('tool-1');
        });
        expect(lastFrame()).toContain('Description for tool-1');
        // Content lines 1-4 should be scrolled off
        expect(lastFrame()).not.toContain('c1-01');
        expect(lastFrame()).not.toContain('c1-04');
        // Line 6 and 7 should be visible (terminalHeight=5 means only 2 lines of content show below 3-line header)
        expect(lastFrame()).toContain('c1-06');
        expect(lastFrame()).toContain('c1-07');
        expect(lastFrame()).toMatchSnapshot();
        // Scroll further so tool-1 is completely gone and tool-2's header should be stuck
        await act(async () => {
            listRef?.scrollBy(17);
        });
        await waitFor(() => {
            expect(lastFrame()).toContain('tool-2');
        });
        expect(lastFrame()).toContain('Description for tool-2');
        // tool-1 should be gone now (both header and content)
        expect(lastFrame()).not.toContain('tool-1');
        expect(lastFrame()).toMatchSnapshot();
    });
    it('verifies that ShellToolMessage in a ToolGroupMessage in a ScrollableList has sticky headers', async () => {
        const toolCalls = [
            {
                ...createToolCall('1', SHELL_COMMAND_NAME, 'shell'),
                status: ToolCallStatus.Success,
            },
        ];
        const terminalWidth = 80;
        const terminalHeight = 5;
        let listRef = null;
        const TestComponent = () => {
            const internalRef = useRef(null);
            useEffect(() => {
                listRef = internalRef.current;
            }, []);
            return (_jsx(ScrollableList, { ref: internalRef, data: ['item1'], renderItem: () => (_jsx(ToolGroupMessage, { groupId: 1, toolCalls: toolCalls, terminalWidth: terminalWidth - 2 })), estimatedItemHeight: () => 30, keyExtractor: (item) => item, hasFocus: true }));
        };
        const { lastFrame } = renderWithProviders(_jsx(Box, { height: terminalHeight, children: _jsx(TestComponent, {}) }), {
            width: terminalWidth,
            uiState: { terminalWidth },
        });
        await waitFor(() => {
            expect(lastFrame()).toContain(SHELL_COMMAND_NAME);
        });
        expect(lastFrame()).toMatchSnapshot();
        // Scroll down
        await act(async () => {
            listRef?.scrollBy(5);
        });
        await waitFor(() => {
            expect(lastFrame()).toContain(SHELL_COMMAND_NAME);
        });
        expect(lastFrame()).toContain('shell-06');
        expect(lastFrame()).toMatchSnapshot();
    });
});
//# sourceMappingURL=ToolStickyHeaderRegression.test.js.map