import { jsx as _jsx } from "react/jsx-runtime";
/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { describe, it, expect, vi, beforeEach, afterEach, } from 'vitest';
import { render, cleanup } from 'ink-testing-library';
import { AppContainer } from './AppContainer.js';
import { makeFakeConfig } from '@google/gemini-cli-core';
import { useQuotaAndFallback } from './hooks/useQuotaAndFallback.js';
import { UIStateContext } from './contexts/UIStateContext.js';
import { UIActionsContext, } from './contexts/UIActionsContext.js';
import { useContext } from 'react';
// Helper component will read the context values provided by AppContainer
// so we can assert against them in our tests.
let capturedUIState;
let capturedUIActions;
function TestContextConsumer() {
    capturedUIState = useContext(UIStateContext);
    capturedUIActions = useContext(UIActionsContext);
    return null;
}
vi.mock('./App.js', () => ({
    App: TestContextConsumer,
}));
vi.mock('ink', async (importOriginal) => {
    const original = await importOriginal();
    return {
        ...original,
        measureElement: vi.fn(),
    };
});
vi.mock('./hooks/useQuotaAndFallback.js');
vi.mock('./hooks/useHistoryManager.js');
vi.mock('./hooks/useThemeCommand.js');
vi.mock('./auth/useAuth.js');
vi.mock('./hooks/useEditorSettings.js');
vi.mock('./hooks/useSettingsCommand.js');
vi.mock('./hooks/useModelCommand.js');
vi.mock('./hooks/slashCommandProcessor.js');
vi.mock('./hooks/useConsoleMessages.js');
vi.mock('./hooks/useTerminalSize.js', () => ({
    useTerminalSize: vi.fn(() => ({ columns: 80, rows: 24 })),
}));
vi.mock('./hooks/useGeminiStream.js');
vi.mock('./hooks/vim.js');
vi.mock('./hooks/useFocus.js');
vi.mock('./hooks/useBracketedPaste.js');
vi.mock('./hooks/useKeypress.js');
vi.mock('./hooks/useLoadingIndicator.js');
vi.mock('./hooks/useFolderTrust.js');
vi.mock('./hooks/useMessageQueue.js');
vi.mock('./hooks/useAutoAcceptIndicator.js');
vi.mock('./hooks/useWorkspaceMigration.js');
vi.mock('./hooks/useGitBranchName.js');
vi.mock('./contexts/VimModeContext.js');
vi.mock('./contexts/SessionContext.js');
vi.mock('./components/shared/text-buffer.js');
vi.mock('./hooks/useLogger.js');
// Mock external utilities
vi.mock('../utils/events.js');
vi.mock('../utils/handleAutoUpdate.js');
vi.mock('./utils/ConsolePatcher.js');
vi.mock('../utils/cleanup.js');
import { useHistory } from './hooks/useHistoryManager.js';
import { useThemeCommand } from './hooks/useThemeCommand.js';
import { useAuthCommand } from './auth/useAuth.js';
import { useEditorSettings } from './hooks/useEditorSettings.js';
import { useSettingsCommand } from './hooks/useSettingsCommand.js';
import { useModelCommand } from './hooks/useModelCommand.js';
import { useSlashCommandProcessor } from './hooks/slashCommandProcessor.js';
import { useConsoleMessages } from './hooks/useConsoleMessages.js';
import { useGeminiStream } from './hooks/useGeminiStream.js';
import { useVim } from './hooks/vim.js';
import { useFolderTrust } from './hooks/useFolderTrust.js';
import { useMessageQueue } from './hooks/useMessageQueue.js';
import { useAutoAcceptIndicator } from './hooks/useAutoAcceptIndicator.js';
import { useWorkspaceMigration } from './hooks/useWorkspaceMigration.js';
import { useGitBranchName } from './hooks/useGitBranchName.js';
import { useVimMode } from './contexts/VimModeContext.js';
import { useSessionStats } from './contexts/SessionContext.js';
import { useTextBuffer } from './components/shared/text-buffer.js';
import { useLogger } from './hooks/useLogger.js';
import { useLoadingIndicator } from './hooks/useLoadingIndicator.js';
import { measureElement } from 'ink';
import { useTerminalSize } from './hooks/useTerminalSize.js';
import { ShellExecutionService } from '@google/gemini-cli-core';
describe('AppContainer State Management', () => {
    let mockConfig;
    let mockSettings;
    let mockInitResult;
    // Create typed mocks for all hooks
    const mockedUseQuotaAndFallback = useQuotaAndFallback;
    const mockedUseHistory = useHistory;
    const mockedUseThemeCommand = useThemeCommand;
    const mockedUseAuthCommand = useAuthCommand;
    const mockedUseEditorSettings = useEditorSettings;
    const mockedUseSettingsCommand = useSettingsCommand;
    const mockedUseModelCommand = useModelCommand;
    const mockedUseSlashCommandProcessor = useSlashCommandProcessor;
    const mockedUseConsoleMessages = useConsoleMessages;
    const mockedUseGeminiStream = useGeminiStream;
    const mockedUseVim = useVim;
    const mockedUseFolderTrust = useFolderTrust;
    const mockedUseMessageQueue = useMessageQueue;
    const mockedUseAutoAcceptIndicator = useAutoAcceptIndicator;
    const mockedUseWorkspaceMigration = useWorkspaceMigration;
    const mockedUseGitBranchName = useGitBranchName;
    const mockedUseVimMode = useVimMode;
    const mockedUseSessionStats = useSessionStats;
    const mockedUseTextBuffer = useTextBuffer;
    const mockedUseLogger = useLogger;
    const mockedUseLoadingIndicator = useLoadingIndicator;
    beforeEach(() => {
        vi.clearAllMocks();
        capturedUIState = null;
        capturedUIActions = null;
        // **Provide a default return value for EVERY mocked hook.**
        mockedUseQuotaAndFallback.mockReturnValue({
            proQuotaRequest: null,
            handleProQuotaChoice: vi.fn(),
        });
        mockedUseHistory.mockReturnValue({
            history: [],
            addItem: vi.fn(),
            updateItem: vi.fn(),
            clearItems: vi.fn(),
            loadHistory: vi.fn(),
        });
        mockedUseThemeCommand.mockReturnValue({
            isThemeDialogOpen: false,
            openThemeDialog: vi.fn(),
            handleThemeSelect: vi.fn(),
            handleThemeHighlight: vi.fn(),
        });
        mockedUseAuthCommand.mockReturnValue({
            authState: 'authenticated',
            setAuthState: vi.fn(),
            authError: null,
            onAuthError: vi.fn(),
        });
        mockedUseEditorSettings.mockReturnValue({
            isEditorDialogOpen: false,
            openEditorDialog: vi.fn(),
            handleEditorSelect: vi.fn(),
            exitEditorDialog: vi.fn(),
        });
        mockedUseSettingsCommand.mockReturnValue({
            isSettingsDialogOpen: false,
            openSettingsDialog: vi.fn(),
            closeSettingsDialog: vi.fn(),
        });
        mockedUseModelCommand.mockReturnValue({
            isModelDialogOpen: false,
            openModelDialog: vi.fn(),
            closeModelDialog: vi.fn(),
        });
        mockedUseSlashCommandProcessor.mockReturnValue({
            handleSlashCommand: vi.fn(),
            slashCommands: [],
            pendingHistoryItems: [],
            commandContext: {},
            shellConfirmationRequest: null,
            confirmationRequest: null,
        });
        mockedUseConsoleMessages.mockReturnValue({
            consoleMessages: [],
            handleNewMessage: vi.fn(),
            clearConsoleMessages: vi.fn(),
        });
        mockedUseGeminiStream.mockReturnValue({
            streamingState: 'idle',
            submitQuery: vi.fn(),
            initError: null,
            pendingHistoryItems: [],
            thought: null,
            cancelOngoingRequest: vi.fn(),
        });
        mockedUseVim.mockReturnValue({ handleInput: vi.fn() });
        mockedUseFolderTrust.mockReturnValue({
            isFolderTrustDialogOpen: false,
            handleFolderTrustSelect: vi.fn(),
            isRestarting: false,
        });
        mockedUseMessageQueue.mockReturnValue({
            messageQueue: [],
            addMessage: vi.fn(),
            clearQueue: vi.fn(),
            getQueuedMessagesText: vi.fn().mockReturnValue(''),
        });
        mockedUseAutoAcceptIndicator.mockReturnValue(false);
        mockedUseWorkspaceMigration.mockReturnValue({
            showWorkspaceMigrationDialog: false,
            workspaceExtensions: [],
            onWorkspaceMigrationDialogOpen: vi.fn(),
            onWorkspaceMigrationDialogClose: vi.fn(),
        });
        mockedUseGitBranchName.mockReturnValue('main');
        mockedUseVimMode.mockReturnValue({
            isVimEnabled: false,
            toggleVimEnabled: vi.fn(),
        });
        mockedUseSessionStats.mockReturnValue({ stats: {} });
        mockedUseTextBuffer.mockReturnValue({
            text: '',
            setText: vi.fn(),
            // Add other properties if AppContainer uses them
        });
        mockedUseLogger.mockReturnValue({
            getPreviousUserMessages: vi.fn().mockResolvedValue([]),
        });
        mockedUseLoadingIndicator.mockReturnValue({
            elapsedTime: '0.0s',
            currentLoadingPhrase: '',
        });
        // Mock Config
        mockConfig = makeFakeConfig();
        // Mock LoadedSettings
        mockSettings = {
            merged: {
                hideBanner: false,
                hideFooter: false,
                hideTips: false,
                showMemoryUsage: false,
                theme: 'default',
            },
        };
        // Mock InitializationResult
        mockInitResult = {
            themeError: null,
            authError: null,
            shouldOpenAuthDialog: false,
            geminiMdFileCount: 0,
        };
    });
    afterEach(() => {
        cleanup();
    });
    describe('Basic Rendering', () => {
        it('renders without crashing with minimal props', () => {
            expect(() => {
                render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
            }).not.toThrow();
        });
        it('renders with startup warnings', () => {
            const startupWarnings = ['Warning 1', 'Warning 2'];
            expect(() => {
                render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, startupWarnings: startupWarnings, version: "1.0.0", initializationResult: mockInitResult }));
            }).not.toThrow();
        });
    });
    describe('State Initialization', () => {
        it('initializes with theme error from initialization result', () => {
            const initResultWithError = {
                ...mockInitResult,
                themeError: 'Failed to load theme',
            };
            expect(() => {
                render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: initResultWithError }));
            }).not.toThrow();
        });
        it('handles debug mode state', () => {
            const debugConfig = makeFakeConfig();
            vi.spyOn(debugConfig, 'getDebugMode').mockReturnValue(true);
            expect(() => {
                render(_jsx(AppContainer, { config: debugConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
            }).not.toThrow();
        });
    });
    describe('Context Providers', () => {
        it('provides AppContext with correct values', () => {
            const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "2.0.0", initializationResult: mockInitResult }));
            // Should render and unmount cleanly
            expect(() => unmount()).not.toThrow();
        });
        it('provides UIStateContext with state management', () => {
            expect(() => {
                render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
            }).not.toThrow();
        });
        it('provides UIActionsContext with action handlers', () => {
            expect(() => {
                render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
            }).not.toThrow();
        });
        it('provides ConfigContext with config object', () => {
            expect(() => {
                render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
            }).not.toThrow();
        });
    });
    describe('Settings Integration', () => {
        it('handles settings with all display options disabled', () => {
            const settingsAllHidden = {
                merged: {
                    hideBanner: true,
                    hideFooter: true,
                    hideTips: true,
                    showMemoryUsage: false,
                },
            };
            expect(() => {
                render(_jsx(AppContainer, { config: mockConfig, settings: settingsAllHidden, version: "1.0.0", initializationResult: mockInitResult }));
            }).not.toThrow();
        });
        it('handles settings with memory usage enabled', () => {
            const settingsWithMemory = {
                merged: {
                    hideBanner: false,
                    hideFooter: false,
                    hideTips: false,
                    showMemoryUsage: true,
                },
            };
            expect(() => {
                render(_jsx(AppContainer, { config: mockConfig, settings: settingsWithMemory, version: "1.0.0", initializationResult: mockInitResult }));
            }).not.toThrow();
        });
    });
    describe('Version Handling', () => {
        it.each(['1.0.0', '2.1.3-beta', '3.0.0-nightly'])('handles version format: %s', (version) => {
            expect(() => {
                render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: version, initializationResult: mockInitResult }));
            }).not.toThrow();
        });
    });
    describe('Error Handling', () => {
        it('handles config methods that might throw', () => {
            const errorConfig = makeFakeConfig();
            vi.spyOn(errorConfig, 'getModel').mockImplementation(() => {
                throw new Error('Config error');
            });
            // Should still render without crashing - errors should be handled internally
            expect(() => {
                render(_jsx(AppContainer, { config: errorConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
            }).not.toThrow();
        });
        it('handles undefined settings gracefully', () => {
            const undefinedSettings = {
                merged: {},
            };
            expect(() => {
                render(_jsx(AppContainer, { config: mockConfig, settings: undefinedSettings, version: "1.0.0", initializationResult: mockInitResult }));
            }).not.toThrow();
        });
    });
    describe('Provider Hierarchy', () => {
        it('establishes correct provider nesting order', () => {
            // This tests that all the context providers are properly nested
            // and that the component tree can be built without circular dependencies
            const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
            expect(() => unmount()).not.toThrow();
        });
    });
    describe('Quota and Fallback Integration', () => {
        it('passes a null proQuotaRequest to UIStateContext by default', () => {
            // The default mock from beforeEach already sets proQuotaRequest to null
            render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
            // Assert that the context value is as expected
            expect(capturedUIState.proQuotaRequest).toBeNull();
        });
        it('passes a valid proQuotaRequest to UIStateContext when provided by the hook', () => {
            // Arrange: Create a mock request object that a UI dialog would receive
            const mockRequest = {
                failedModel: 'gemini-pro',
                fallbackModel: 'gemini-flash',
                resolve: vi.fn(),
            };
            mockedUseQuotaAndFallback.mockReturnValue({
                proQuotaRequest: mockRequest,
                handleProQuotaChoice: vi.fn(),
            });
            // Act: Render the container
            render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
            // Assert: The mock request is correctly passed through the context
            expect(capturedUIState.proQuotaRequest).toEqual(mockRequest);
        });
        it('passes the handleProQuotaChoice function to UIActionsContext', () => {
            // Arrange: Create a mock handler function
            const mockHandler = vi.fn();
            mockedUseQuotaAndFallback.mockReturnValue({
                proQuotaRequest: null,
                handleProQuotaChoice: mockHandler,
            });
            // Act: Render the container
            render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
            // Assert: The action in the context is the mock handler we provided
            expect(capturedUIActions.handleProQuotaChoice).toBe(mockHandler);
            // You can even verify that the plumbed function is callable
            capturedUIActions.handleProQuotaChoice('auth');
            expect(mockHandler).toHaveBeenCalledWith('auth');
        });
    });
    describe('Terminal Height Calculation', () => {
        const mockedMeasureElement = measureElement;
        const mockedUseTerminalSize = useTerminalSize;
        it('should prevent terminal height from being less than 1', () => {
            const resizePtySpy = vi.spyOn(ShellExecutionService, 'resizePty');
            // Arrange: Simulate a small terminal and a large footer
            mockedUseTerminalSize.mockReturnValue({ columns: 80, rows: 5 });
            mockedMeasureElement.mockReturnValue({ width: 80, height: 10 }); // Footer is taller than the screen
            mockedUseGeminiStream.mockReturnValue({
                streamingState: 'idle',
                submitQuery: vi.fn(),
                initError: null,
                pendingHistoryItems: [],
                thought: null,
                cancelOngoingRequest: vi.fn(),
                activePtyId: 'some-id',
            });
            render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
            // Assert: The shell should be resized to a minimum height of 1, not a negative number.
            // The old code would have tried to set a negative height.
            expect(resizePtySpy).toHaveBeenCalled();
            const lastCall = resizePtySpy.mock.calls[resizePtySpy.mock.calls.length - 1];
            // Check the height argument specifically
            expect(lastCall[2]).toBe(1);
        });
    });
    describe('Keyboard Input Handling', () => {
        it('should block quit command during authentication', () => {
            mockedUseAuthCommand.mockReturnValue({
                authState: 'unauthenticated',
                setAuthState: vi.fn(),
                authError: null,
                onAuthError: vi.fn(),
            });
            const mockHandleSlashCommand = vi.fn();
            mockedUseSlashCommandProcessor.mockReturnValue({
                handleSlashCommand: mockHandleSlashCommand,
                slashCommands: [],
                pendingHistoryItems: [],
                commandContext: {},
                shellConfirmationRequest: null,
                confirmationRequest: null,
            });
            render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
            expect(mockHandleSlashCommand).not.toHaveBeenCalledWith('/quit');
        });
        it('should prevent exit command when text buffer has content', () => {
            mockedUseTextBuffer.mockReturnValue({
                text: 'some user input',
                setText: vi.fn(),
            });
            const mockHandleSlashCommand = vi.fn();
            mockedUseSlashCommandProcessor.mockReturnValue({
                handleSlashCommand: mockHandleSlashCommand,
                slashCommands: [],
                pendingHistoryItems: [],
                commandContext: {},
                shellConfirmationRequest: null,
                confirmationRequest: null,
            });
            render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
            expect(mockHandleSlashCommand).not.toHaveBeenCalledWith('/quit');
        });
        it('should require double Ctrl+C to exit when dialogs are open', () => {
            vi.useFakeTimers();
            mockedUseThemeCommand.mockReturnValue({
                isThemeDialogOpen: true,
                openThemeDialog: vi.fn(),
                handleThemeSelect: vi.fn(),
                handleThemeHighlight: vi.fn(),
            });
            const mockHandleSlashCommand = vi.fn();
            mockedUseSlashCommandProcessor.mockReturnValue({
                handleSlashCommand: mockHandleSlashCommand,
                slashCommands: [],
                pendingHistoryItems: [],
                commandContext: {},
                shellConfirmationRequest: null,
                confirmationRequest: null,
            });
            render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
            expect(mockHandleSlashCommand).not.toHaveBeenCalledWith('/quit');
            expect(mockHandleSlashCommand).not.toHaveBeenCalledWith('/quit');
            vi.useRealTimers();
        });
        it('should cancel ongoing request on first Ctrl+C', () => {
            const mockCancelOngoingRequest = vi.fn();
            mockedUseGeminiStream.mockReturnValue({
                streamingState: 'responding',
                submitQuery: vi.fn(),
                initError: null,
                pendingHistoryItems: [],
                thought: null,
                cancelOngoingRequest: mockCancelOngoingRequest,
            });
            const mockHandleSlashCommand = vi.fn();
            mockedUseSlashCommandProcessor.mockReturnValue({
                handleSlashCommand: mockHandleSlashCommand,
                slashCommands: [],
                pendingHistoryItems: [],
                commandContext: {},
                shellConfirmationRequest: null,
                confirmationRequest: null,
            });
            render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
            expect(mockHandleSlashCommand).not.toHaveBeenCalledWith('/quit');
        });
        it('should reset Ctrl+C state after timeout', () => {
            vi.useFakeTimers();
            const mockHandleSlashCommand = vi.fn();
            mockedUseSlashCommandProcessor.mockReturnValue({
                handleSlashCommand: mockHandleSlashCommand,
                slashCommands: [],
                pendingHistoryItems: [],
                commandContext: {},
                shellConfirmationRequest: null,
                confirmationRequest: null,
            });
            render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
            expect(mockHandleSlashCommand).not.toHaveBeenCalledWith('/quit');
            vi.advanceTimersByTime(1001);
            expect(mockHandleSlashCommand).not.toHaveBeenCalledWith('/quit');
            vi.useRealTimers();
        });
    });
    describe('Model Dialog Integration', () => {
        it('should provide isModelDialogOpen in the UIStateContext', () => {
            mockedUseModelCommand.mockReturnValue({
                isModelDialogOpen: true,
                openModelDialog: vi.fn(),
                closeModelDialog: vi.fn(),
            });
            render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
            expect(capturedUIState.isModelDialogOpen).toBe(true);
        });
        it('should provide model dialog actions in the UIActionsContext', () => {
            const mockCloseModelDialog = vi.fn();
            mockedUseModelCommand.mockReturnValue({
                isModelDialogOpen: false,
                openModelDialog: vi.fn(),
                closeModelDialog: mockCloseModelDialog,
            });
            render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
            // Verify that the actions are correctly passed through context
            capturedUIActions.closeModelDialog();
            expect(mockCloseModelDialog).toHaveBeenCalled();
        });
    });
});
//# sourceMappingURL=AppContainer.test.js.map