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, saveApiKey, debugLogger, coreEvents, CoreEvent, } from 'sixth-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 { SixthAuthHandler } from './components/SixthAuthHandler.js';
import { SubscriptionBlockedScreen } from './components/SubscriptionBlockedScreen.js';
import { SubscriptionManager } from 'sixth-cli-core';
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, config.getEnableExtensionReloading());
    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 [isBackgroundInitComplete, setIsBackgroundInitComplete] = 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 () => {
            try {
                await config.initialize();
                setConfigInitialized(true);
                // Check if background initialization is complete
                const checkBackgroundInit = () => {
                    if (config.getGeminiClient()?.isInitialized?.()) {
                        setIsBackgroundInitComplete(true);
                    }
                    else {
                        // Check again in 100ms
                        setTimeout(checkBackgroundInit, 100);
                    }
                };
                setTimeout(checkBackgroundInit, 50);
            }
            catch (error) {
                console.timeEnd('[INIT] Config initialization');
                console.error('[INIT] Config initialization failed:', error);
                throw error;
            }
        })();
        registerCleanup(async () => {
            const ideClient = await IdeClient.getInstance();
            await ideClient.disconnect();
        });
    }, [config]);
    useEffect(() => setUpdateHandler(historyManager.addItem, setUpdateInfo), [historyManager.addItem]);
    // Subscribe to fallback mode changes from core
    useEffect(() => {
        const handleFallbackModeChanged = () => {
            const effectiveModel = getEffectiveModel();
            setCurrentModel(effectiveModel);
        };
        coreEvents.on(CoreEvent.FallbackModeChanged, handleFallbackModeChanged);
        return () => {
            coreEvents.off(CoreEvent.FallbackModeChanged, handleFallbackModeChanged);
        };
    }, [getEffectiveModel]);
    // Subscribe to subscription blocked events from core
    useEffect(() => {
        const handleSubscriptionBlocked = (payload) => {
            if (payload.shouldBlock) {
                debugLogger.log(`User has exceeded token limit and should be blocked (${payload.totalTokensUsed} tokens)`);
                // Update subscription status
                Promise.resolve().then(async () => {
                    const status = await SubscriptionManager.getSubscriptionStatus();
                    setSubscriptionStatus(status);
                    setIsSubscriptionBlocked(true);
                });
            }
        };
        coreEvents.on(CoreEvent.SubscriptionBlocked, handleSubscriptionBlocked);
        return () => {
            coreEvents.off(CoreEvent.SubscriptionBlocked, handleSubscriptionBlocked);
        };
    }, []);
    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, apiKeyDefaultValue, reloadApiKey, } = useAuthCommand(settings, config);
    const { proQuotaRequest, handleProQuotaChoice } = useQuotaAndFallback({
        config,
        historyManager,
        userTier,
        setAuthState,
        setModelSwitchedFromQuotaError,
    });
    // Derive auth state variables for backward compatibility with UIStateContext
    const isAuthenticating = authState === AuthState.Unauthenticated;
    const isSixthAuthRequired = authState === AuthState.SixthAuthRequired;
    // Subscription management state
    const [subscriptionStatus, setSubscriptionStatus] = useState(null);
    const [isSubscriptionBlocked, setIsSubscriptionBlocked] = useState(false);
    // NOTE: Subscription check disabled during startup to prevent slow initialization
    // Subscription will be checked after first API call via token tracking
    // Subscription refresh handler
    const handleSubscriptionRefresh = useCallback(() => {
        // Run async operations in a Promise to avoid blocking
        Promise.resolve().then(async () => {
            try {
                // First refresh the user info from API
                await SubscriptionManager.refreshUserInfo();
                // Then get updated subscription status
                const updatedStatus = await SubscriptionManager.getSubscriptionStatus();
                setSubscriptionStatus(updatedStatus);
                // If user is now a subscriber or hasn't exceeded limit, unblock them
                if (!updatedStatus.shouldBlock) {
                    setIsSubscriptionBlocked(false);
                    debugLogger.log('Subscription updated - user unblocked');
                    // Force complete input reset after unblocking with terminal state cleanup
                    setTimeout(() => {
                        setInputResetKey(prev => prev + 1);
                        buffer.setText('');
                        // Force stdin to be in raw mode again
                        if (process.stdin.setRawMode) {
                            process.stdin.setRawMode(false);
                            process.stdin.setRawMode(true);
                        }
                    }, 100);
                }
                else {
                    debugLogger.log('Subscription still requires upgrade');
                    // Keep blocked
                    setIsSubscriptionBlocked(true);
                }
            }
            catch (error) {
                debugLogger.error('Failed to refresh subscription status:', error);
                // On error, keep current state
            }
        });
    }, []);
    // Check subscription status after system is ready
    useEffect(() => {
        // Check subscription status once the system is fully initialized
        if (isConfigInitialized && isBackgroundInitComplete && !isAuthenticating) {
            Promise.resolve().then(async () => {
                try {
                    const status = await SubscriptionManager.getSubscriptionStatus();
                    setSubscriptionStatus(status);
                    console.log(`[SUBSCRIPTION] Status check: shouldBlock=${status.shouldBlock}, tokens=${status.totalTokensUsed}, subscriber=${status.isSubscriber}`);
                    if (status.shouldBlock) {
                        console.log(`[SUBSCRIPTION] User has exceeded token limit and should be blocked (${status.totalTokensUsed} tokens)`);
                        setIsSubscriptionBlocked(true);
                    }
                }
                catch (error) {
                    console.error('[SUBSCRIPTION] Failed to check subscription status:', error);
                }
            });
        }
    }, [isConfigInitialized, isBackgroundInitComplete, isAuthenticating]);
    // 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]);
    const handleApiKeySubmit = useCallback(async (apiKey) => {
        try {
            if (!apiKey.trim() && apiKey.length > 1) {
                onAuthError('API key cannot be empty string with length greater than 1.');
                return;
            }
            await saveApiKey(apiKey);
            await reloadApiKey();
            await config.refreshAuth(AuthType.USE_GEMINI);
            setAuthState(AuthState.Authenticated);
        }
        catch (e) {
            onAuthError(`Failed to save API key: ${e instanceof Error ? e.message : String(e)}`);
        }
    }, [setAuthState, onAuthError, reloadApiKey, config]);
    const handleApiKeyCancel = useCallback(() => {
        // Go back to auth method selection
        setAuthState(AuthState.SixthAuthRequired);
    }, [setAuthState]);
    // Force input reset after auth
    const [inputResetKey, setInputResetKey] = useState(0);
    // Sixth authentication handlers
    const handleSixthAuthComplete = useCallback((userInfo) => {
        debugLogger.log(`Sixth authentication completed for user: ${userInfo.email}`);
        // Reset auth state to trigger Gemini auth flow
        setAuthState(AuthState.Unauthenticated);
        // Force complete input reset with terminal state cleanup
        setTimeout(() => {
            setInputResetKey(prev => prev + 1);
            buffer.setText('');
            // Force stdin to be in raw mode again
            if (process.stdin.setRawMode) {
                process.stdin.setRawMode(false);
                process.stdin.setRawMode(true);
            }
        }, 100);
    }, [setAuthState]);
    const handleSixthAuthError = useCallback((error) => {
        debugLogger.error('Sixth authentication failed:', error);
        onAuthError(`Sixth authentication failed: ${error}`);
    }, [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.SixthAuthRequired),
        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: isConfigInitialized && isBackgroundInitComplete,
        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)
     * - Background initialization not complete
     * - Authentication screens
     * - Subscription blocked screens
     * - Any future streaming states not explicitly allowed
     */
    const isInputActive = !initError &&
        !isProcessing &&
        !!slashCommands &&
        isConfigInitialized &&
        isBackgroundInitComplete &&
        !isSixthAuthRequired &&
        !isSubscriptionBlocked &&
        (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 &&
            isBackgroundInitComplete &&
            !initialPromptSubmitted.current &&
            !isAuthenticating &&
            !isThemeDialogOpen &&
            !isEditorDialogOpen &&
            !showPrivacyNotice &&
            geminiClient?.isInitialized?.()) {
            handleFinalSubmit(initialPrompt);
            initialPromptSubmitted.current = true;
        }
    }, [
        initialPrompt,
        isConfigInitialized,
        isBackgroundInitComplete,
        handleFinalSubmit,
        isAuthenticating,
        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 Sixth 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 Sixth 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 ||
        isEditorDialogOpen ||
        showPrivacyNotice ||
        showIdeRestartPrompt ||
        !!proQuotaRequest ||
        false; // Disabled: authState === AuthState.AwaitingApiKeyInput (using hardcoded key)
    const pendingHistoryItems = useMemo(() => [...pendingSlashCommandHistoryItems, ...pendingGeminiHistoryItems], [pendingSlashCommandHistoryItems, pendingGeminiHistoryItems]);
    const uiState = useMemo(() => ({
        history: historyManager.history,
        historyManager,
        isThemeDialogOpen,
        themeError,
        isAuthenticating,
        isConfigInitialized,
        isBackgroundInitComplete,
        authError,
        isAwaitingApiKeyInput: false, // Disabled: authState === AuthState.AwaitingApiKeyInput (using hardcoded key)
        apiKeyDefaultValue,
        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,
        isBackgroundInitComplete,
        authError,
        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,
        apiKeyDefaultValue,
        authState,
    ]);
    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,
        handleApiKeySubmit,
        handleApiKeyCancel,
    }), [
        handleThemeSelect,
        closeThemeDialog,
        handleThemeHighlight,
        handleAuthSelect,
        setAuthState,
        onAuthError,
        handleEditorSelect,
        exitEditorDialog,
        exitPrivacyNotice,
        closeSettingsDialog,
        closeModelDialog,
        closePermissionsDialog,
        setShellModeActive,
        vimHandleInput,
        handleIdePromptComplete,
        handleFolderTrustSelect,
        setConstrainHeight,
        handleEscapePromptChange,
        refreshStatic,
        handleFinalSubmit,
        handleClearScreen,
        handleProQuotaChoice,
        setQueueErrorMessage,
        popAllMessages,
        handleApiKeySubmit,
        handleApiKeyCancel,
    ]);
    // If Sixth authentication is required, show the auth handler
    if (isSixthAuthRequired) {
        return (_jsx(SixthAuthHandler, { onAuthComplete: handleSixthAuthComplete, onAuthError: handleSixthAuthError }));
    }
    // If subscription is blocked, show the subscription blocked screen
    if (isSubscriptionBlocked && subscriptionStatus) {
        return (_jsx(SubscriptionBlockedScreen, { status: subscriptionStatus, onRefresh: handleSubscriptionRefresh }));
    }
    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, {}, inputResetKey) }) }) }) }) }));
};
//# sourceMappingURL=AppContainer.js.map