import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { render } from '../../test-utils/render.js';
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { BackgroundShellDisplay } from './BackgroundShellDisplay.js';
import {} from '../hooks/shellCommandProcessor.js';
import { ShellExecutionService } from '@google/gemini-cli-core';
import { act } from 'react';
import {} from '../contexts/KeypressContext.js';
import { ScrollProvider } from '../contexts/ScrollProvider.js';
import { Box } from 'ink';
// Mock dependencies
const mockDismissBackgroundShell = vi.fn();
const mockSetActiveBackgroundShellPid = vi.fn();
const mockSetIsBackgroundShellListOpen = vi.fn();
vi.mock('../contexts/UIActionsContext.js', () => ({
    useUIActions: () => ({
        dismissBackgroundShell: mockDismissBackgroundShell,
        setActiveBackgroundShellPid: mockSetActiveBackgroundShellPid,
        setIsBackgroundShellListOpen: mockSetIsBackgroundShellListOpen,
    }),
}));
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
    const actual = await importOriginal();
    return {
        ...actual,
        ShellExecutionService: {
            resizePty: vi.fn(),
            subscribe: vi.fn(() => vi.fn()),
        },
    };
});
// Mock AnsiOutputText since it's a complex component
vi.mock('./AnsiOutput.js', () => ({
    AnsiOutputText: ({ data }) => {
        if (typeof data === 'string')
            return _jsx(_Fragment, { children: data });
        // Simple serialization for object data
        return _jsx(_Fragment, { children: JSON.stringify(data) });
    },
}));
// Mock useKeypress
let keypressHandlers = [];
vi.mock('../hooks/useKeypress.js', () => ({
    useKeypress: vi.fn((handler, { isActive }) => {
        keypressHandlers.push({ handler, isActive });
    }),
}));
const simulateKey = (key) => {
    const fullKey = createMockKey(key);
    keypressHandlers.forEach(({ handler, isActive }) => {
        if (isActive) {
            handler(fullKey);
        }
    });
};
vi.mock('../contexts/MouseContext.js', () => ({
    useMouseContext: vi.fn(() => ({
        subscribe: vi.fn(),
        unsubscribe: vi.fn(),
    })),
    useMouse: vi.fn(),
}));
// Mock ScrollableList
vi.mock('./shared/ScrollableList.js', () => ({
    SCROLL_TO_ITEM_END: 999999,
    ScrollableList: vi.fn(({ data, renderItem, }) => (_jsx(Box, { flexDirection: "column", children: data.map((item, index) => (_jsx(Box, { children: renderItem({ item, index }) }, index))) }))),
}));
afterEach(() => {
    vi.restoreAllMocks();
});
const createMockKey = (overrides) => ({
    name: '',
    ctrl: false,
    alt: false,
    cmd: false,
    shift: false,
    insertable: false,
    sequence: '',
    ...overrides,
});
describe('<BackgroundShellDisplay />', () => {
    const mockShells = new Map();
    const shell1 = {
        pid: 1001,
        command: 'npm start',
        output: 'Starting server...',
        isBinary: false,
        binaryBytesReceived: 0,
        status: 'running',
    };
    const shell2 = {
        pid: 1002,
        command: 'tail -f log.txt',
        output: 'Log entry 1',
        isBinary: false,
        binaryBytesReceived: 0,
        status: 'running',
    };
    beforeEach(() => {
        vi.clearAllMocks();
        mockShells.clear();
        mockShells.set(shell1.pid, shell1);
        mockShells.set(shell2.pid, shell2);
        keypressHandlers = [];
    });
    it('renders the output of the active shell', async () => {
        const width = 80;
        const { lastFrame, waitUntilReady, unmount } = render(_jsx(ScrollProvider, { children: _jsx(BackgroundShellDisplay, { shells: mockShells, activePid: shell1.pid, width: width, height: 24, isFocused: false, isListOpenProp: false }) }), width);
        await waitUntilReady();
        expect(lastFrame()).toMatchSnapshot();
        unmount();
    });
    it('renders tabs for multiple shells', async () => {
        const width = 100;
        const { lastFrame, waitUntilReady, unmount } = render(_jsx(ScrollProvider, { children: _jsx(BackgroundShellDisplay, { shells: mockShells, activePid: shell1.pid, width: width, height: 24, isFocused: false, isListOpenProp: false }) }), width);
        await waitUntilReady();
        expect(lastFrame()).toMatchSnapshot();
        unmount();
    });
    it('highlights the focused state', async () => {
        const width = 80;
        const { lastFrame, waitUntilReady, unmount } = render(_jsx(ScrollProvider, { children: _jsx(BackgroundShellDisplay, { shells: mockShells, activePid: shell1.pid, width: width, height: 24, isFocused: true, isListOpenProp: false }) }), width);
        await waitUntilReady();
        expect(lastFrame()).toMatchSnapshot();
        unmount();
    });
    it('resizes the PTY on mount and when dimensions change', async () => {
        const width = 80;
        const { rerender, waitUntilReady, unmount } = render(_jsx(ScrollProvider, { children: _jsx(BackgroundShellDisplay, { shells: mockShells, activePid: shell1.pid, width: width, height: 24, isFocused: false, isListOpenProp: false }) }), width);
        await waitUntilReady();
        expect(ShellExecutionService.resizePty).toHaveBeenCalledWith(shell1.pid, 76, 21);
        rerender(_jsx(ScrollProvider, { children: _jsx(BackgroundShellDisplay, { shells: mockShells, activePid: shell1.pid, width: 100, height: 30, isFocused: false, isListOpenProp: false }) }));
        await waitUntilReady();
        expect(ShellExecutionService.resizePty).toHaveBeenCalledWith(shell1.pid, 96, 27);
        unmount();
    });
    it('renders the process list when isListOpenProp is true', async () => {
        const width = 80;
        const { lastFrame, waitUntilReady, unmount } = render(_jsx(ScrollProvider, { children: _jsx(BackgroundShellDisplay, { shells: mockShells, activePid: shell1.pid, width: width, height: 24, isFocused: true, isListOpenProp: true }) }), width);
        await waitUntilReady();
        expect(lastFrame()).toMatchSnapshot();
        unmount();
    });
    it('selects the current process and closes the list when Ctrl+L is pressed in list view', async () => {
        const width = 80;
        const { waitUntilReady, unmount } = render(_jsx(ScrollProvider, { children: _jsx(BackgroundShellDisplay, { shells: mockShells, activePid: shell1.pid, width: width, height: 24, isFocused: true, isListOpenProp: true }) }), width);
        await waitUntilReady();
        // Simulate down arrow to select the second process (handled by RadioButtonSelect)
        await act(async () => {
            simulateKey({ name: 'down' });
        });
        await waitUntilReady();
        // Simulate Ctrl+L (handled by BackgroundShellDisplay)
        await act(async () => {
            simulateKey({ name: 'l', ctrl: true });
        });
        await waitUntilReady();
        expect(mockSetActiveBackgroundShellPid).toHaveBeenCalledWith(shell2.pid);
        expect(mockSetIsBackgroundShellListOpen).toHaveBeenCalledWith(false);
        unmount();
    });
    it('kills the highlighted process when Ctrl+K is pressed in list view', async () => {
        const width = 80;
        const { waitUntilReady, unmount } = render(_jsx(ScrollProvider, { children: _jsx(BackgroundShellDisplay, { shells: mockShells, activePid: shell1.pid, width: width, height: 24, isFocused: true, isListOpenProp: true }) }), width);
        await waitUntilReady();
        // Initial state: shell1 (active) is highlighted
        // Move to shell2
        await act(async () => {
            simulateKey({ name: 'down' });
        });
        await waitUntilReady();
        // Press Ctrl+K
        await act(async () => {
            simulateKey({ name: 'k', ctrl: true });
        });
        await waitUntilReady();
        expect(mockDismissBackgroundShell).toHaveBeenCalledWith(shell2.pid);
        unmount();
    });
    it('kills the active process when Ctrl+K is pressed in output view', async () => {
        const width = 80;
        const { waitUntilReady, unmount } = render(_jsx(ScrollProvider, { children: _jsx(BackgroundShellDisplay, { shells: mockShells, activePid: shell1.pid, width: width, height: 24, isFocused: true, isListOpenProp: false }) }), width);
        await waitUntilReady();
        await act(async () => {
            simulateKey({ name: 'k', ctrl: true });
        });
        await waitUntilReady();
        expect(mockDismissBackgroundShell).toHaveBeenCalledWith(shell1.pid);
        unmount();
    });
    it('scrolls to active shell when list opens', async () => {
        // shell2 is active
        const width = 80;
        const { lastFrame, waitUntilReady, unmount } = render(_jsx(ScrollProvider, { children: _jsx(BackgroundShellDisplay, { shells: mockShells, activePid: shell2.pid, width: width, height: 24, isFocused: true, isListOpenProp: true }) }), width);
        await waitUntilReady();
        expect(lastFrame()).toMatchSnapshot();
        unmount();
    });
    it('keeps exit code status color even when selected', async () => {
        const exitedShell = {
            pid: 1003,
            command: 'exit 0',
            output: '',
            isBinary: false,
            binaryBytesReceived: 0,
            status: 'exited',
            exitCode: 0,
        };
        mockShells.set(exitedShell.pid, exitedShell);
        const width = 80;
        const { lastFrame, waitUntilReady, unmount } = render(_jsx(ScrollProvider, { children: _jsx(BackgroundShellDisplay, { shells: mockShells, activePid: exitedShell.pid, width: width, height: 24, isFocused: true, isListOpenProp: true }) }), width);
        await waitUntilReady();
        expect(lastFrame()).toMatchSnapshot();
        unmount();
    });
});
//# sourceMappingURL=BackgroundShellDisplay.test.js.map