import { jsx as _jsx } from "react/jsx-runtime";
/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { useMemo, useState, useCallback, useEffect, useRef, useLayoutEffect, } from 'react';
import { measureElement } from 'ink';
import { App } from './App.js';
import { AppContext } from './contexts/AppContext.js';
import { UIStateContext } from './contexts/UIStateContext.js';
import { UIActionsContext, } from './contexts/UIActionsContext.js';
import { ConfigContext } from './contexts/ConfigContext.js';
import { ToolCallStatus, AuthState, } from './types.js';
import { MessageType, StreamingState } from './types.js';
import { DEFAULT_GEMINI_FLASH_MODEL, IdeClient, ideContextStore, getErrorMessage, getAllGeminiMdFilenames, AuthType, clearCachedCredentialFile, recordExitFail, ShellExecutionService, debugLogger, coreEvents, CoreEvent, } from '@google/gemini-cli-core';
import { validateAuthMethod } from '../config/auth.js';
import { loadHierarchicalGeminiMemory } from '../config/config.js';
import { getPolicyErrorsForUI } from '../config/policy.js';
import process from 'node:process';
import { useHistory } from './hooks/useHistoryManager.js';
import { useMemoryMonitor } from './hooks/useMemoryMonitor.js';
import { useThemeCommand } from './hooks/useThemeCommand.js';
import { useAuthCommand } from './auth/useAuth.js';
import { useQuotaAndFallback } from './hooks/useQuotaAndFallback.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 { useVimMode } from './contexts/VimModeContext.js';
import { useConsoleMessages } from './hooks/useConsoleMessages.js';
import { useTerminalSize } from './hooks/useTerminalSize.js';
import { calculatePromptWidths } from './components/InputPrompt.js';
import { useStdout, useStdin } from 'ink';
import { calculateMainAreaWidth } from './utils/ui-sizing.js';
import ansiEscapes from 'ansi-escapes';
import * as fs from 'node:fs';
import { basename } from 'node:path';
import { computeWindowTitle } from '../utils/windowTitle.js';
import { useTextBuffer } from './components/shared/text-buffer.js';
import { useLogger } from './hooks/useLogger.js';
import { useGeminiStream } from './hooks/useGeminiStream.js';
import { useVim } from './hooks/vim.js';
import { SettingScope } from '../config/settings.js';
import {} from '../core/initializer.js';
import { useFocus } from './hooks/useFocus.js';
import { useBracketedPaste } from './hooks/useBracketedPaste.js';
import { useKeypress } from './hooks/useKeypress.js';
import { keyMatchers, Command } from './keyMatchers.js';
import { useLoadingIndicator } from './hooks/useLoadingIndicator.js';
import { useFolderTrust } from './hooks/useFolderTrust.js';
import { useIdeTrustListener } from './hooks/useIdeTrustListener.js';
import {} from './IdeIntegrationNudge.js';
import { appEvents, AppEvent } from '../utils/events.js';
import {} from './utils/updateCheck.js';
import { setUpdateHandler } from '../utils/handleAutoUpdate.js';
import { ConsolePatcher } from './utils/ConsolePatcher.js';
import { registerCleanup, runExitCleanup } from '../utils/cleanup.js';
import { useMessageQueue } from './hooks/useMessageQueue.js';
import { useAutoAcceptIndicator } from './hooks/useAutoAcceptIndicator.js';
import { useSessionStats } from './contexts/SessionContext.js';
import { useGitBranchName } from './hooks/useGitBranchName.js';
import { useConfirmUpdateRequests, useExtensionUpdates, } from './hooks/useExtensionUpdates.js';
import { ShellFocusContext } from './contexts/ShellFocusContext.js';
import {} from '../config/extension-manager.js';
import { requestConsentInteractive } from '../config/extensions/consent.js';
const CTRL_EXIT_PROMPT_DURATION_MS = 1000;
const QUEUE_ERROR_DISPLAY_DURATION_MS = 3000;
function isToolExecuting(pendingHistoryItems) {
    return pendingHistoryItems.some((item) => {
        if (item && item.type === 'tool_group') {
            return item.tools.some((tool) => ToolCallStatus.Executing === tool.status);
        }
        return false;
    });
}
/**
 * The fraction of the terminal width to allocate to the shell.
 * This provides horizontal padding.
 */
const SHELL_WIDTH_FRACTION = 0.89;
/**
 * The number of lines to subtract from the available terminal height
 * for the shell. This provides vertical padding and space for other UI elements.
 */
const SHELL_HEIGHT_PADDING = 10;
export const AppContainer = (props) => {
    const { settings, config, initializationResult } = props;
    const historyManager = useHistory();
    useMemoryMonitor(historyManager);
    const [corgiMode, setCorgiMode] = useState(false);
    const [debugMessage, setDebugMessage] = useState('');
    const [quittingMessages, setQuittingMessages] = useState(null);
    const [showPrivacyNotice, setShowPrivacyNotice] = useState(false);
    const [themeError, setThemeError] = useState(initializationResult.themeError);
    const [isProcessing, setIsProcessing] = useState(false);
    const [embeddedShellFocused, setEmbeddedShellFocused] = useState(false);
    const [showDebugProfiler, setShowDebugProfiler] = useState(false);
    const [geminiMdFileCount, setGeminiMdFileCount] = useState(initializationResult.geminiMdFileCount);
    const [shellModeActive, setShellModeActive] = useState(false);
    const [modelSwitchedFromQuotaError, setModelSwitchedFromQuotaError] = useState(false);
    const [historyRemountKey, setHistoryRemountKey] = useState(0);
    const [updateInfo, setUpdateInfo] = useState(null);
    const [isTrustedFolder, setIsTrustedFolder] = useState(config.isTrustedFolder());
    const [queueErrorMessage, setQueueErrorMessage] = useState(null);
    const extensionManager = config.getExtensionLoader();
    // We are in the interactive CLI, update how we request consent and settings.
    extensionManager.setRequestConsent((description) => requestConsentInteractive(description, addConfirmUpdateExtensionRequest));
    extensionManager.setRequestSetting();
    const { addConfirmUpdateExtensionRequest, confirmUpdateExtensionRequests } = useConfirmUpdateRequests();
    const { extensionsUpdateState, extensionsUpdateStateInternal, dispatchExtensionStateUpdate, } = useExtensionUpdates(extensionManager, historyManager.addItem);
    const [isPermissionsDialogOpen, setPermissionsDialogOpen] = useState(false);
    const openPermissionsDialog = useCallback(() => setPermissionsDialogOpen(true), []);
    const closePermissionsDialog = useCallback(() => setPermissionsDialogOpen(false), []);
    const toggleDebugProfiler = useCallback(() => setShowDebugProfiler((prev) => !prev), []);
    // Helper to determine the effective model, considering the fallback state.
    const getEffectiveModel = useCallback(() => {
        if (config.isInFallbackMode()) {
            return DEFAULT_GEMINI_FLASH_MODEL;
        }
        return config.getModel();
    }, [config]);
    const [currentModel, setCurrentModel] = useState(getEffectiveModel());
    const [userTier, setUserTier] = useState(undefined);
    const [isConfigInitialized, setConfigInitialized] = useState(false);
    const logger = useLogger(config.storage);
    const [userMessages, setUserMessages] = useState([]);
    // Terminal and layout hooks
    const { columns: terminalWidth, rows: terminalHeight } = useTerminalSize();
    const { stdin, setRawMode } = useStdin();
    const { stdout } = useStdout();
    // Additional hooks moved from App.tsx
    const { stats: sessionStats } = useSessionStats();
    const branchName = useGitBranchName(config.getTargetDir());
    // Layout measurements
    const mainControlsRef = useRef(null);
    // For performance profiling only
    const rootUiRef = useRef(null);
    const originalTitleRef = useRef(computeWindowTitle(basename(config.getTargetDir())));
    const lastTitleRef = useRef(null);
    const staticExtraHeight = 3;
    useEffect(() => {
        (async () => {
            // Note: the program will not work if this fails so let errors be
            // handled by the global catch.
            await config.initialize();
            setConfigInitialized(true);
        })();
        registerCleanup(async () => {
            const ideClient = await IdeClient.getInstance();
            await ideClient.disconnect();
        });
    }, [config]);
    useEffect(() => setUpdateHandler(historyManager.addItem, setUpdateInfo), [historyManager.addItem]);
    // Subscribe to fallback mode and model changes from core
    useEffect(() => {
        const handleFallbackModeChanged = () => {
            const effectiveModel = getEffectiveModel();
            setCurrentModel(effectiveModel);
        };
        const handleModelChanged = (payload) => {
            setCurrentModel(payload.model);
        };
        coreEvents.on(CoreEvent.FallbackModeChanged, handleFallbackModeChanged);
        coreEvents.on(CoreEvent.ModelChanged, handleModelChanged);
        return () => {
            coreEvents.off(CoreEvent.FallbackModeChanged, handleFallbackModeChanged);
            coreEvents.off(CoreEvent.ModelChanged, handleModelChanged);
        };
    }, [getEffectiveModel]);
    const { consoleMessages, handleNewMessage, clearConsoleMessages: clearConsoleMessagesState, } = useConsoleMessages();
    useEffect(() => {
        const consolePatcher = new ConsolePatcher({
            onNewMessage: handleNewMessage,
            debugMode: config.getDebugMode(),
        });
        consolePatcher.patch();
        registerCleanup(consolePatcher.cleanup);
    }, [handleNewMessage, config]);
    const mainAreaWidth = calculateMainAreaWidth(terminalWidth, settings);
    // Derive widths for InputPrompt using shared helper
    const { inputWidth, suggestionsWidth } = useMemo(() => {
        const { inputWidth, suggestionsWidth } = calculatePromptWidths(mainAreaWidth);
        return { inputWidth, suggestionsWidth };
    }, [mainAreaWidth]);
    const staticAreaMaxItemHeight = Math.max(terminalHeight * 4, 100);
    const isValidPath = useCallback((filePath) => {
        try {
            return fs.existsSync(filePath) && fs.statSync(filePath).isFile();
        }
        catch (_e) {
            return false;
        }
    }, []);
    const buffer = useTextBuffer({
        initialText: '',
        viewport: { height: 10, width: inputWidth },
        stdin,
        setRawMode,
        isValidPath,
        shellModeActive,
    });
    useEffect(() => {
        const fetchUserMessages = async () => {
            const pastMessagesRaw = (await logger?.getPreviousUserMessages()) || [];
            const currentSessionUserMessages = historyManager.history
                .filter((item) => item.type === 'user' &&
                typeof item.text === 'string' &&
                item.text.trim() !== '')
                .map((item) => item.text)
                .reverse();
            const combinedMessages = [
                ...currentSessionUserMessages,
                ...pastMessagesRaw,
            ];
            const deduplicatedMessages = [];
            if (combinedMessages.length > 0) {
                deduplicatedMessages.push(combinedMessages[0]);
                for (let i = 1; i < combinedMessages.length; i++) {
                    if (combinedMessages[i] !== combinedMessages[i - 1]) {
                        deduplicatedMessages.push(combinedMessages[i]);
                    }
                }
            }
            setUserMessages(deduplicatedMessages.reverse());
        };
        fetchUserMessages();
    }, [historyManager.history, logger]);
    const refreshStatic = useCallback(() => {
        stdout.write(ansiEscapes.clearTerminal);
        setHistoryRemountKey((prev) => prev + 1);
    }, [setHistoryRemountKey, stdout]);
    const { isThemeDialogOpen, openThemeDialog, closeThemeDialog, handleThemeSelect, handleThemeHighlight, } = useThemeCommand(settings, setThemeError, historyManager.addItem, initializationResult.themeError);
    const { authState, setAuthState, authError, onAuthError } = useAuthCommand(settings, config);
    const { proQuotaRequest, handleProQuotaChoice } = useQuotaAndFallback({
        config,
        historyManager,
        userTier,
        setAuthState,
        setModelSwitchedFromQuotaError,
    });
    // Derive auth state variables for backward compatibility with UIStateContext
    const isAuthDialogOpen = authState === AuthState.Updating;
    const isAuthenticating = authState === AuthState.Unauthenticated;
    // Create handleAuthSelect wrapper for backward compatibility
    const handleAuthSelect = useCallback(async (authType, scope) => {
        if (authType) {
            await clearCachedCredentialFile();
            settings.setValue(scope, 'security.auth.selectedType', authType);
            try {
                await config.refreshAuth(authType);
                setAuthState(AuthState.Authenticated);
            }
            catch (e) {
                onAuthError(`Failed to authenticate: ${e instanceof Error ? e.message : String(e)}`);
                return;
            }
            if (authType === AuthType.LOGIN_WITH_GOOGLE &&
                config.isBrowserLaunchSuppressed()) {
                await runExitCleanup();
                debugLogger.log(`
----------------------------------------------------------------
Logging in with Google... Please restart Gemini CLI to continue.
----------------------------------------------------------------
          `);
                process.exit(0);
            }
        }
        setAuthState(AuthState.Authenticated);
    }, [settings, config, setAuthState, onAuthError]);
    // Sync user tier from config when authentication changes
    useEffect(() => {
        // Only sync when not currently authenticating
        if (authState === AuthState.Authenticated) {
            setUserTier(config.getUserTier());
        }
    }, [config, authState]);
    // Check for enforced auth type mismatch
    useEffect(() => {
        if (settings.merged.security?.auth?.enforcedType &&
            settings.merged.security?.auth.selectedType &&
            settings.merged.security?.auth.enforcedType !==
                settings.merged.security?.auth.selectedType) {
            onAuthError(`Authentication is enforced to be ${settings.merged.security?.auth.enforcedType}, but you are currently using ${settings.merged.security?.auth.selectedType}.`);
        }
        else if (settings.merged.security?.auth?.selectedType &&
            !settings.merged.security?.auth?.useExternal) {
            const error = validateAuthMethod(settings.merged.security.auth.selectedType);
            if (error) {
                onAuthError(error);
            }
        }
    }, [
        settings.merged.security?.auth?.selectedType,
        settings.merged.security?.auth?.enforcedType,
        settings.merged.security?.auth?.useExternal,
        onAuthError,
    ]);
    const [editorError, setEditorError] = useState(null);
    const { isEditorDialogOpen, openEditorDialog, handleEditorSelect, exitEditorDialog, } = useEditorSettings(settings, setEditorError, historyManager.addItem);
    const { isSettingsDialogOpen, openSettingsDialog, closeSettingsDialog } = useSettingsCommand();
    const { isModelDialogOpen, openModelDialog, closeModelDialog } = useModelCommand();
    const { toggleVimEnabled } = useVimMode();
    const slashCommandActions = useMemo(() => ({
        openAuthDialog: () => setAuthState(AuthState.Updating),
        openThemeDialog,
        openEditorDialog,
        openPrivacyNotice: () => setShowPrivacyNotice(true),
        openSettingsDialog,
        openModelDialog,
        openPermissionsDialog,
        quit: (messages) => {
            setQuittingMessages(messages);
            setTimeout(async () => {
                await runExitCleanup();
                process.exit(0);
            }, 100);
        },
        setDebugMessage,
        toggleCorgiMode: () => setCorgiMode((prev) => !prev),
        toggleDebugProfiler,
        dispatchExtensionStateUpdate,
        addConfirmUpdateExtensionRequest,
    }), [
        setAuthState,
        openThemeDialog,
        openEditorDialog,
        openSettingsDialog,
        openModelDialog,
        setQuittingMessages,
        setDebugMessage,
        setShowPrivacyNotice,
        setCorgiMode,
        dispatchExtensionStateUpdate,
        openPermissionsDialog,
        addConfirmUpdateExtensionRequest,
        toggleDebugProfiler,
    ]);
    const { handleSlashCommand, slashCommands, pendingHistoryItems: pendingSlashCommandHistoryItems, commandContext, shellConfirmationRequest, confirmationRequest, } = useSlashCommandProcessor(config, settings, historyManager.addItem, historyManager.clearItems, historyManager.loadHistory, refreshStatic, toggleVimEnabled, setIsProcessing, setGeminiMdFileCount, slashCommandActions, extensionsUpdateStateInternal, isConfigInitialized);
    const performMemoryRefresh = useCallback(async () => {
        historyManager.addItem({
            type: MessageType.INFO,
            text: 'Refreshing hierarchical memory (GEMINI.md or other context files)...',
        }, Date.now());
        try {
            const { memoryContent, fileCount, filePaths } = await loadHierarchicalGeminiMemory(process.cwd(), settings.merged.context?.loadMemoryFromIncludeDirectories
                ? config.getWorkspaceContext().getDirectories()
                : [], config.getDebugMode(), config.getFileService(), settings.merged, config.getExtensionLoader(), config.isTrustedFolder(), settings.merged.context?.importFormat || 'tree', // Use setting or default to 'tree'
            config.getFileFilteringOptions());
            config.setUserMemory(memoryContent);
            config.setGeminiMdFileCount(fileCount);
            config.setGeminiMdFilePaths(filePaths);
            setGeminiMdFileCount(fileCount);
            historyManager.addItem({
                type: MessageType.INFO,
                text: `Memory refreshed successfully. ${memoryContent.length > 0
                    ? `Loaded ${memoryContent.length} characters from ${fileCount} file(s).`
                    : 'No memory content found.'}`,
            }, Date.now());
            if (config.getDebugMode()) {
                debugLogger.log(`[DEBUG] Refreshed memory content in config: ${memoryContent.substring(0, 200)}...`);
            }
        }
        catch (error) {
            const errorMessage = getErrorMessage(error);
            historyManager.addItem({
                type: MessageType.ERROR,
                text: `Error refreshing memory: ${errorMessage}`,
            }, Date.now());
            debugLogger.warn('Error refreshing memory:', error);
        }
    }, [config, historyManager, settings.merged]);
    const cancelHandlerRef = useRef(() => { });
    const getPreferredEditor = useCallback(() => settings.merged.general?.preferredEditor, [settings.merged.general?.preferredEditor]);
    const onCancelSubmit = useCallback(() => {
        cancelHandlerRef.current();
    }, []);
    const { streamingState, submitQuery, initError, pendingHistoryItems: pendingGeminiHistoryItems, thought, cancelOngoingRequest, handleApprovalModeChange, activePtyId, loopDetectionConfirmationRequest, } = useGeminiStream(config.getGeminiClient(), historyManager.history, historyManager.addItem, config, settings, setDebugMessage, handleSlashCommand, shellModeActive, getPreferredEditor, onAuthError, performMemoryRefresh, modelSwitchedFromQuotaError, setModelSwitchedFromQuotaError, refreshStatic, onCancelSubmit, setEmbeddedShellFocused, terminalWidth, terminalHeight, embeddedShellFocused);
    // Auto-accept indicator
    const showAutoAcceptIndicator = useAutoAcceptIndicator({
        config,
        addItem: historyManager.addItem,
        onApprovalModeChange: handleApprovalModeChange,
    });
    const { messageQueue, addMessage, clearQueue, getQueuedMessagesText, popAllMessages, } = useMessageQueue({
        isConfigInitialized,
        streamingState,
        submitQuery,
    });
    cancelHandlerRef.current = useCallback(() => {
        const pendingHistoryItems = [
            ...pendingSlashCommandHistoryItems,
            ...pendingGeminiHistoryItems,
        ];
        if (isToolExecuting(pendingHistoryItems)) {
            buffer.setText(''); // Just clear the prompt
            return;
        }
        const lastUserMessage = userMessages.at(-1);
        let textToSet = lastUserMessage || '';
        const queuedText = getQueuedMessagesText();
        if (queuedText) {
            textToSet = textToSet ? `${textToSet}\n\n${queuedText}` : queuedText;
            clearQueue();
        }
        if (textToSet) {
            buffer.setText(textToSet);
        }
    }, [
        buffer,
        userMessages,
        getQueuedMessagesText,
        clearQueue,
        pendingSlashCommandHistoryItems,
        pendingGeminiHistoryItems,
    ]);
    const handleFinalSubmit = useCallback((submittedValue) => {
        addMessage(submittedValue);
    }, [addMessage]);
    const handleClearScreen = useCallback(() => {
        historyManager.clearItems();
        clearConsoleMessagesState();
        console.clear();
        refreshStatic();
    }, [historyManager, clearConsoleMessagesState, refreshStatic]);
    const { handleInput: vimHandleInput } = useVim(buffer, handleFinalSubmit);
    /**
     * Determines if the input prompt should be active and accept user input.
     * Input is disabled during:
     * - Initialization errors
     * - Slash command processing
     * - Tool confirmations (WaitingForConfirmation state)
     * - Any future streaming states not explicitly allowed
     */
    const isInputActive = !initError &&
        !isProcessing &&
        !!slashCommands &&
        (streamingState === StreamingState.Idle ||
            streamingState === StreamingState.Responding) &&
        !proQuotaRequest;
    const [controlsHeight, setControlsHeight] = useState(0);
    useLayoutEffect(() => {
        if (mainControlsRef.current) {
            const fullFooterMeasurement = measureElement(mainControlsRef.current);
            if (fullFooterMeasurement.height > 0) {
                setControlsHeight(fullFooterMeasurement.height);
            }
        }
    }, [buffer, terminalWidth, terminalHeight]);
    // Compute available terminal height based on controls measurement
    const availableTerminalHeight = Math.max(0, terminalHeight - controlsHeight - staticExtraHeight - 2);
    config.setShellExecutionConfig({
        terminalWidth: Math.floor(terminalWidth * SHELL_WIDTH_FRACTION),
        terminalHeight: Math.max(Math.floor(availableTerminalHeight - SHELL_HEIGHT_PADDING), 1),
        pager: settings.merged.tools?.shell?.pager,
        showColor: settings.merged.tools?.shell?.showColor,
    });
    const isFocused = useFocus();
    useBracketedPaste();
    // Context file names computation
    const contextFileNames = useMemo(() => {
        const fromSettings = settings.merged.context?.fileName;
        return fromSettings
            ? Array.isArray(fromSettings)
                ? fromSettings
                : [fromSettings]
            : getAllGeminiMdFilenames();
    }, [settings.merged.context?.fileName]);
    // Initial prompt handling
    const initialPrompt = useMemo(() => config.getQuestion(), [config]);
    const initialPromptSubmitted = useRef(false);
    const geminiClient = config.getGeminiClient();
    useEffect(() => {
        if (activePtyId) {
            ShellExecutionService.resizePty(activePtyId, Math.floor(terminalWidth * SHELL_WIDTH_FRACTION), Math.max(Math.floor(availableTerminalHeight - SHELL_HEIGHT_PADDING), 1));
        }
    }, [terminalWidth, availableTerminalHeight, activePtyId]);
    useEffect(() => {
        if (initialPrompt &&
            isConfigInitialized &&
            !initialPromptSubmitted.current &&
            !isAuthenticating &&
            !isAuthDialogOpen &&
            !isThemeDialogOpen &&
            !isEditorDialogOpen &&
            !showPrivacyNotice &&
            geminiClient?.isInitialized?.()) {
            handleFinalSubmit(initialPrompt);
            initialPromptSubmitted.current = true;
        }
    }, [
        initialPrompt,
        isConfigInitialized,
        handleFinalSubmit,
        isAuthenticating,
        isAuthDialogOpen,
        isThemeDialogOpen,
        isEditorDialogOpen,
        showPrivacyNotice,
        geminiClient,
    ]);
    const [idePromptAnswered, setIdePromptAnswered] = useState(false);
    const [currentIDE, setCurrentIDE] = useState(null);
    useEffect(() => {
        const getIde = async () => {
            const ideClient = await IdeClient.getInstance();
            const currentIde = ideClient.getCurrentIde();
            setCurrentIDE(currentIde || null);
        };
        getIde();
    }, []);
    const shouldShowIdePrompt = Boolean(currentIDE &&
        !config.getIdeMode() &&
        !settings.merged.ide?.hasSeenNudge &&
        !idePromptAnswered);
    const [showErrorDetails, setShowErrorDetails] = useState(false);
    const [showFullTodos, setShowFullTodos] = useState(false);
    const [renderMarkdown, setRenderMarkdown] = useState(true);
    const [ctrlCPressCount, setCtrlCPressCount] = useState(0);
    const ctrlCTimerRef = useRef(null);
    const [ctrlDPressCount, setCtrlDPressCount] = useState(0);
    const ctrlDTimerRef = useRef(null);
    const [constrainHeight, setConstrainHeight] = useState(true);
    const [ideContextState, setIdeContextState] = useState();
    const [showEscapePrompt, setShowEscapePrompt] = useState(false);
    const [showIdeRestartPrompt, setShowIdeRestartPrompt] = useState(false);
    const { isFolderTrustDialogOpen, handleFolderTrustSelect, isRestarting } = useFolderTrust(settings, setIsTrustedFolder, historyManager.addItem);
    const { needsRestart: ideNeedsRestart, restartReason: ideTrustRestartReason, } = useIdeTrustListener();
    const isInitialMount = useRef(true);
    useEffect(() => {
        if (ideNeedsRestart) {
            // IDE trust changed, force a restart.
            setShowIdeRestartPrompt(true);
        }
    }, [ideNeedsRestart]);
    useEffect(() => {
        if (queueErrorMessage) {
            const timer = setTimeout(() => {
                setQueueErrorMessage(null);
            }, QUEUE_ERROR_DISPLAY_DURATION_MS);
            return () => clearTimeout(timer);
        }
        return undefined;
    }, [queueErrorMessage, setQueueErrorMessage]);
    useEffect(() => {
        if (isInitialMount.current) {
            isInitialMount.current = false;
            return;
        }
        const handler = setTimeout(() => {
            refreshStatic();
        }, 300);
        return () => {
            clearTimeout(handler);
        };
    }, [terminalWidth, refreshStatic]);
    useEffect(() => {
        const unsubscribe = ideContextStore.subscribe(setIdeContextState);
        setIdeContextState(ideContextStore.get());
        return unsubscribe;
    }, []);
    useEffect(() => {
        const openDebugConsole = () => {
            setShowErrorDetails(true);
            setConstrainHeight(false);
        };
        appEvents.on(AppEvent.OpenDebugConsole, openDebugConsole);
        const logErrorHandler = (errorMessage) => {
            handleNewMessage({
                type: 'error',
                content: String(errorMessage),
                count: 1,
            });
        };
        appEvents.on(AppEvent.LogError, logErrorHandler);
        // Emit any policy errors that were stored during config loading
        // Only show these when message bus integration is enabled, as policies
        // are only active when the message bus is being used.
        if (config.getEnableMessageBusIntegration()) {
            const policyErrors = getPolicyErrorsForUI();
            if (policyErrors.length > 0) {
                for (const error of policyErrors) {
                    appEvents.emit(AppEvent.LogError, error);
                }
            }
        }
        return () => {
            appEvents.off(AppEvent.OpenDebugConsole, openDebugConsole);
            appEvents.off(AppEvent.LogError, logErrorHandler);
        };
    }, [handleNewMessage, config]);
    useEffect(() => {
        if (ctrlCTimerRef.current) {
            clearTimeout(ctrlCTimerRef.current);
            ctrlCTimerRef.current = null;
        }
        if (ctrlCPressCount > 2) {
            recordExitFail(config);
        }
        if (ctrlCPressCount > 1) {
            handleSlashCommand('/quit');
        }
        else {
            ctrlCTimerRef.current = setTimeout(() => {
                setCtrlCPressCount(0);
                ctrlCTimerRef.current = null;
            }, CTRL_EXIT_PROMPT_DURATION_MS);
        }
    }, [ctrlCPressCount, config, setCtrlCPressCount, handleSlashCommand]);
    useEffect(() => {
        if (ctrlDTimerRef.current) {
            clearTimeout(ctrlDTimerRef.current);
            ctrlCTimerRef.current = null;
        }
        if (ctrlDPressCount > 2) {
            recordExitFail(config);
        }
        if (ctrlDPressCount > 1) {
            handleSlashCommand('/quit');
        }
        else {
            ctrlDTimerRef.current = setTimeout(() => {
                setCtrlDPressCount(0);
                ctrlDTimerRef.current = null;
            }, CTRL_EXIT_PROMPT_DURATION_MS);
        }
    }, [ctrlDPressCount, config, setCtrlDPressCount, handleSlashCommand]);
    const handleEscapePromptChange = useCallback((showPrompt) => {
        setShowEscapePrompt(showPrompt);
    }, []);
    const handleIdePromptComplete = useCallback((result) => {
        if (result.userSelection === 'yes') {
            handleSlashCommand('/ide install');
            settings.setValue(SettingScope.User, 'hasSeenIdeIntegrationNudge', true);
        }
        else if (result.userSelection === 'dismiss') {
            settings.setValue(SettingScope.User, 'hasSeenIdeIntegrationNudge', true);
        }
        setIdePromptAnswered(true);
    }, [handleSlashCommand, settings]);
    const { elapsedTime, currentLoadingPhrase } = useLoadingIndicator(streamingState, settings.merged.ui?.customWittyPhrases);
    const handleGlobalKeypress = useCallback((key) => {
        // Debug log keystrokes if enabled
        if (settings.merged.general?.debugKeystrokeLogging) {
            debugLogger.log('[DEBUG] Keystroke:', JSON.stringify(key));
        }
        if (keyMatchers[Command.QUIT](key)) {
            // If the user presses Ctrl+C, we want to cancel any ongoing requests.
            // This should happen regardless of the count.
            cancelOngoingRequest?.();
            setCtrlCPressCount((prev) => prev + 1);
            return;
        }
        else if (keyMatchers[Command.EXIT](key)) {
            if (buffer.text.length > 0) {
                return;
            }
            setCtrlDPressCount((prev) => prev + 1);
            return;
        }
        let enteringConstrainHeightMode = false;
        if (!constrainHeight) {
            enteringConstrainHeightMode = true;
            setConstrainHeight(true);
        }
        if (keyMatchers[Command.SHOW_ERROR_DETAILS](key)) {
            setShowErrorDetails((prev) => !prev);
        }
        else if (keyMatchers[Command.SHOW_FULL_TODOS](key)) {
            setShowFullTodos((prev) => !prev);
        }
        else if (keyMatchers[Command.TOGGLE_MARKDOWN](key)) {
            setRenderMarkdown((prev) => {
                const newValue = !prev;
                // Force re-render of static content
                refreshStatic();
                return newValue;
            });
        }
        else if (keyMatchers[Command.TOGGLE_IDE_CONTEXT_DETAIL](key) &&
            config.getIdeMode() &&
            ideContextState) {
            handleSlashCommand('/ide status');
        }
        else if (keyMatchers[Command.SHOW_MORE_LINES](key) &&
            !enteringConstrainHeightMode) {
            setConstrainHeight(false);
        }
        else if (keyMatchers[Command.TOGGLE_SHELL_INPUT_FOCUS](key)) {
            if (activePtyId || embeddedShellFocused) {
                setEmbeddedShellFocused((prev) => !prev);
            }
        }
    }, [
        constrainHeight,
        setConstrainHeight,
        setShowErrorDetails,
        config,
        ideContextState,
        setCtrlCPressCount,
        buffer.text.length,
        setCtrlDPressCount,
        handleSlashCommand,
        cancelOngoingRequest,
        activePtyId,
        embeddedShellFocused,
        settings.merged.general?.debugKeystrokeLogging,
        refreshStatic,
    ]);
    useKeypress(handleGlobalKeypress, { isActive: true });
    // Update terminal title with Gemini CLI status and thoughts
    useEffect(() => {
        // Respect both showStatusInTitle and hideWindowTitle settings
        if (!settings.merged.ui?.showStatusInTitle ||
            settings.merged.ui?.hideWindowTitle)
            return;
        let title;
        if (streamingState === StreamingState.Idle) {
            title = originalTitleRef.current;
        }
        else {
            const statusText = thought?.subject
                ?.replace(/[\r\n]+/g, ' ')
                .substring(0, 80);
            title = statusText || originalTitleRef.current;
        }
        // Pad the title to a fixed width to prevent taskbar icon resizing.
        const paddedTitle = title.padEnd(80, ' ');
        // Only update the title if it's different from the last value we set
        if (lastTitleRef.current !== paddedTitle) {
            lastTitleRef.current = paddedTitle;
            stdout.write(`\x1b]2;${paddedTitle}\x07`);
        }
        // Note: We don't need to reset the window title on exit because Gemini CLI is already doing that elsewhere
    }, [
        streamingState,
        thought,
        settings.merged.ui?.showStatusInTitle,
        settings.merged.ui?.hideWindowTitle,
        stdout,
    ]);
    useEffect(() => {
        const handleUserFeedback = (payload) => {
            let type;
            switch (payload.severity) {
                case 'error':
                    type = MessageType.ERROR;
                    break;
                case 'warning':
                    type = MessageType.WARNING;
                    break;
                case 'info':
                    type = MessageType.INFO;
                    break;
                default:
                    throw new Error(`Unexpected severity for user feedback: ${payload.severity}`);
            }
            historyManager.addItem({
                type,
                text: payload.message,
            }, Date.now());
            // If there is an attached error object, log it to the debug drawer.
            if (payload.error) {
                debugLogger.warn(`[Feedback Details for "${payload.message}"]`, payload.error);
            }
        };
        coreEvents.on(CoreEvent.UserFeedback, handleUserFeedback);
        // Flush any messages that happened during startup before this component
        // mounted.
        coreEvents.drainFeedbackBacklog();
        return () => {
            coreEvents.off(CoreEvent.UserFeedback, handleUserFeedback);
        };
    }, [historyManager]);
    const filteredConsoleMessages = useMemo(() => {
        if (config.getDebugMode()) {
            return consoleMessages;
        }
        return consoleMessages.filter((msg) => msg.type !== 'debug');
    }, [consoleMessages, config]);
    // Computed values
    const errorCount = useMemo(() => filteredConsoleMessages
        .filter((msg) => msg.type === 'error')
        .reduce((total, msg) => total + msg.count, 0), [filteredConsoleMessages]);
    const nightly = props.version.includes('nightly');
    const dialogsVisible = shouldShowIdePrompt ||
        isFolderTrustDialogOpen ||
        !!shellConfirmationRequest ||
        !!confirmationRequest ||
        confirmUpdateExtensionRequests.length > 0 ||
        !!loopDetectionConfirmationRequest ||
        isThemeDialogOpen ||
        isSettingsDialogOpen ||
        isModelDialogOpen ||
        isPermissionsDialogOpen ||
        isAuthenticating ||
        isAuthDialogOpen ||
        isEditorDialogOpen ||
        showPrivacyNotice ||
        showIdeRestartPrompt ||
        !!proQuotaRequest;
    const pendingHistoryItems = useMemo(() => [...pendingSlashCommandHistoryItems, ...pendingGeminiHistoryItems], [pendingSlashCommandHistoryItems, pendingGeminiHistoryItems]);
    const uiState = useMemo(() => ({
        history: historyManager.history,
        historyManager,
        isThemeDialogOpen,
        themeError,
        isAuthenticating,
        isConfigInitialized,
        authError,
        isAuthDialogOpen,
        editorError,
        isEditorDialogOpen,
        showPrivacyNotice,
        corgiMode,
        debugMessage,
        quittingMessages,
        isSettingsDialogOpen,
        isModelDialogOpen,
        isPermissionsDialogOpen,
        slashCommands,
        pendingSlashCommandHistoryItems,
        commandContext,
        shellConfirmationRequest,
        confirmationRequest,
        confirmUpdateExtensionRequests,
        loopDetectionConfirmationRequest,
        geminiMdFileCount,
        streamingState,
        initError,
        pendingGeminiHistoryItems,
        thought,
        shellModeActive,
        userMessages,
        buffer,
        inputWidth,
        suggestionsWidth,
        isInputActive,
        shouldShowIdePrompt,
        isFolderTrustDialogOpen: isFolderTrustDialogOpen ?? false,
        isTrustedFolder,
        constrainHeight,
        showErrorDetails,
        showFullTodos,
        filteredConsoleMessages,
        ideContextState,
        renderMarkdown,
        ctrlCPressedOnce: ctrlCPressCount >= 1,
        ctrlDPressedOnce: ctrlDPressCount >= 1,
        showEscapePrompt,
        isFocused,
        elapsedTime,
        currentLoadingPhrase,
        historyRemountKey,
        messageQueue,
        queueErrorMessage,
        showAutoAcceptIndicator,
        currentModel,
        userTier,
        proQuotaRequest,
        contextFileNames,
        errorCount,
        availableTerminalHeight,
        mainAreaWidth,
        staticAreaMaxItemHeight,
        staticExtraHeight,
        dialogsVisible,
        pendingHistoryItems,
        nightly,
        branchName,
        sessionStats,
        terminalWidth,
        terminalHeight,
        mainControlsRef,
        rootUiRef,
        currentIDE,
        updateInfo,
        showIdeRestartPrompt,
        ideTrustRestartReason,
        isRestarting,
        extensionsUpdateState,
        activePtyId,
        embeddedShellFocused,
        showDebugProfiler,
    }), [
        isThemeDialogOpen,
        themeError,
        isAuthenticating,
        isConfigInitialized,
        authError,
        isAuthDialogOpen,
        editorError,
        isEditorDialogOpen,
        showPrivacyNotice,
        corgiMode,
        debugMessage,
        quittingMessages,
        isSettingsDialogOpen,
        isModelDialogOpen,
        isPermissionsDialogOpen,
        slashCommands,
        pendingSlashCommandHistoryItems,
        commandContext,
        shellConfirmationRequest,
        confirmationRequest,
        confirmUpdateExtensionRequests,
        loopDetectionConfirmationRequest,
        geminiMdFileCount,
        streamingState,
        initError,
        pendingGeminiHistoryItems,
        thought,
        shellModeActive,
        userMessages,
        buffer,
        inputWidth,
        suggestionsWidth,
        isInputActive,
        shouldShowIdePrompt,
        isFolderTrustDialogOpen,
        isTrustedFolder,
        constrainHeight,
        showErrorDetails,
        showFullTodos,
        filteredConsoleMessages,
        ideContextState,
        renderMarkdown,
        ctrlCPressCount,
        ctrlDPressCount,
        showEscapePrompt,
        isFocused,
        elapsedTime,
        currentLoadingPhrase,
        historyRemountKey,
        messageQueue,
        queueErrorMessage,
        showAutoAcceptIndicator,
        userTier,
        proQuotaRequest,
        contextFileNames,
        errorCount,
        availableTerminalHeight,
        mainAreaWidth,
        staticAreaMaxItemHeight,
        staticExtraHeight,
        dialogsVisible,
        pendingHistoryItems,
        nightly,
        branchName,
        sessionStats,
        terminalWidth,
        terminalHeight,
        mainControlsRef,
        rootUiRef,
        currentIDE,
        updateInfo,
        showIdeRestartPrompt,
        ideTrustRestartReason,
        isRestarting,
        currentModel,
        extensionsUpdateState,
        activePtyId,
        historyManager,
        embeddedShellFocused,
        showDebugProfiler,
    ]);
    const exitPrivacyNotice = useCallback(() => setShowPrivacyNotice(false), [setShowPrivacyNotice]);
    const uiActions = useMemo(() => ({
        handleThemeSelect,
        closeThemeDialog,
        handleThemeHighlight,
        handleAuthSelect,
        setAuthState,
        onAuthError,
        handleEditorSelect,
        exitEditorDialog,
        exitPrivacyNotice,
        closeSettingsDialog,
        closeModelDialog,
        closePermissionsDialog,
        setShellModeActive,
        vimHandleInput,
        handleIdePromptComplete,
        handleFolderTrustSelect,
        setConstrainHeight,
        onEscapePromptChange: handleEscapePromptChange,
        refreshStatic,
        handleFinalSubmit,
        handleClearScreen,
        handleProQuotaChoice,
        setQueueErrorMessage,
        popAllMessages,
    }), [
        handleThemeSelect,
        closeThemeDialog,
        handleThemeHighlight,
        handleAuthSelect,
        setAuthState,
        onAuthError,
        handleEditorSelect,
        exitEditorDialog,
        exitPrivacyNotice,
        closeSettingsDialog,
        closeModelDialog,
        closePermissionsDialog,
        setShellModeActive,
        vimHandleInput,
        handleIdePromptComplete,
        handleFolderTrustSelect,
        setConstrainHeight,
        handleEscapePromptChange,
        refreshStatic,
        handleFinalSubmit,
        handleClearScreen,
        handleProQuotaChoice,
        setQueueErrorMessage,
        popAllMessages,
    ]);
    return (_jsx(UIStateContext.Provider, { value: uiState, children: _jsx(UIActionsContext.Provider, { value: uiActions, children: _jsx(ConfigContext.Provider, { value: config, children: _jsx(AppContext.Provider, { value: {
                        version: props.version,
                        startupWarnings: props.startupWarnings || [],
                    }, children: _jsx(ShellFocusContext.Provider, { value: isFocused, children: _jsx(App, {}) }) }) }) }) }));
};
//# sourceMappingURL=AppContainer.js.map