import { jsx as _jsx } from "react/jsx-runtime";
import { randomBytes } from 'node:crypto';
import React from 'react';
import { createClearMessagesHandler, handleMessageSubmission, } from '../app/utils/app-util.js';
import { ErrorMessage, SuccessMessage, WarningMessage, } from '../components/message-box.js';
import Status from '../components/status.js';
import { getAppConfig } from '../config/index.js';
import { getModelContextLimit } from '../models/index.js';
import { bashExecutor } from '../services/bash-executor.js';
import { CheckpointManager } from '../services/checkpoint-manager.js';
import { generateKey, setKeyGeneratorSessionId } from '../session/key-generator.js';
import { buildSessionHistoryComponents } from '../session/session-history-renderer.js';
import { sessionManager } from '../session/session-manager.js';
import { createTokenizer } from '../tokenization/index.js';
import { getGitStatusSummarySync, } from '../tools/git/utils.js';
import { calculateTokenBreakdown } from '../usage/calculator.js';
import { autoCompactSessionOverrides } from '../utils/auto-compact.js';
import { formatError } from '../utils/error-formatter.js';
import { getLogger } from '../utils/logging/index.js';
import { getLastBuiltPrompt } from '../utils/prompt-builder.js';
/**
 * Consolidates all app handler setup into a single hook
 */
export function useAppHandlers(props) {
    const logger = getLogger();
    // Clear messages handler
    const clearMessages = React.useMemo(() => async () => {
        const baseClear = createClearMessagesHandler(props.updateMessages, props.client);
        await baseClear();
        props.setChatComponents([]);
        props.setCurrentSessionId(null);
        // Reset the key-generator session ID so keys in the new conversation
        // are not prefixed with the cleared session's ID. A fresh random ID
        // will be lazily generated on the next generateKey() call.
        setKeyGeneratorSessionId(randomBytes(4).toString('hex'));
        props.setLiveTaskList(null);
        props.dismissActiveEditor?.();
    }, [
        props.updateMessages,
        props.client,
        props.setChatComponents,
        props.setCurrentSessionId,
        props,
    ]);
    // Cancel handler
    const handleCancel = React.useCallback(() => {
        // Kill any in-flight bash commands immediately. The auto-execute (yolo/
        // headless) path runs bash without mounting the live BashProgress that
        // owns the escape->cancel handler, so aborting the controller alone would
        // leave the command running until it finished naturally. Cancelling here
        // resolves the bash promise right away regardless of execution path.
        const activeBashIds = bashExecutor.getActiveExecutionIds();
        for (const id of activeBashIds) {
            bashExecutor.cancel(id);
        }
        if (props.abortController) {
            logger.info('Cancelling current operation', {
                operation: 'user_cancellation',
                hasAbortController: !!props.abortController,
                activeBashExecutions: activeBashIds.length,
            });
            props.setIsCancelling(true);
            props.abortController.abort();
        }
        else if (activeBashIds.length === 0) {
            logger.debug('Cancel requested but no active operation to cancel');
        }
    }, [props.abortController, props.setIsCancelling, logger, props]);
    // Toggle development mode handler
    const handleToggleDevelopmentMode = React.useCallback(() => {
        props.setDevelopmentMode(currentMode => {
            // Don't allow toggling out of headless via Shift+Tab: it's a
            // non-interactive mode entered by the daemon, not the user.
            if (currentMode === 'headless')
                return currentMode;
            const modes = [
                'normal',
                'auto-accept',
                'yolo',
                'plan',
            ];
            const currentIndex = modes.indexOf(currentMode);
            const nextIndex = (currentIndex + 1) % modes.length;
            const nextMode = modes[nextIndex];
            logger.info('Development mode toggled', {
                previousMode: currentMode,
                nextMode,
                modeIndex: nextIndex,
                totalModes: modes.length,
            });
            return nextMode;
        });
    }, [props.setDevelopmentMode, logger, props]);
    // Show status handler
    const handleShowStatus = React.useCallback(async () => {
        logger.debug('Status display requested', {
            currentProvider: props.currentProvider,
            currentModel: props.currentModel,
            currentTheme: props.currentTheme,
        });
        // Calculate context usage and auto-compact info
        let contextUsage;
        let autoCompactInfo;
        try {
            // Calculate context usage
            const contextLimit = await getModelContextLimit(props.currentModel, {
                providerConfig: props.client?.getProviderConfig(),
            });
            if (contextLimit && props.messages.length > 0) {
                const tokenizer = createTokenizer(props.currentProvider, props.currentModel);
                try {
                    const systemPrompt = getLastBuiltPrompt();
                    const systemMessage = {
                        role: 'system',
                        content: systemPrompt,
                    };
                    const breakdown = calculateTokenBreakdown([systemMessage, ...props.messages], tokenizer, props.getMessageTokens);
                    const percentUsed = (breakdown.total / contextLimit) * 100;
                    contextUsage = {
                        currentTokens: breakdown.total,
                        contextLimit,
                        percentUsed,
                    };
                }
                finally {
                    if (tokenizer.free) {
                        tokenizer.free();
                    }
                }
            }
            // Get auto-compact info
            const config = getAppConfig();
            const autoCompactConfig = config.autoCompact;
            if (autoCompactConfig) {
                const enabled = autoCompactSessionOverrides.enabled !== null
                    ? autoCompactSessionOverrides.enabled
                    : autoCompactConfig.enabled;
                const threshold = autoCompactSessionOverrides.threshold !== null
                    ? autoCompactSessionOverrides.threshold
                    : autoCompactConfig.threshold;
                const mode = autoCompactSessionOverrides.mode !== null
                    ? autoCompactSessionOverrides.mode
                    : autoCompactConfig.mode;
                const hasOverrides = autoCompactSessionOverrides.enabled !== null ||
                    autoCompactSessionOverrides.threshold !== null ||
                    autoCompactSessionOverrides.mode !== null;
                autoCompactInfo = {
                    enabled,
                    threshold,
                    mode,
                    hasOverrides,
                };
            }
        }
        catch (error) {
            logger.debug('Failed to calculate status info', { error });
            // Continue without context usage/auto-compact info
        }
        // Resolve the current git branch for the /status panel. The sync
        // helper reads the .git filesystem directly — same code path as the
        // boot summary, so the two surfaces can't drift. Failures degrade
        // to omitting the line.
        let gitStatus = null;
        try {
            gitStatus = getGitStatusSummarySync();
        }
        catch (error) {
            logger.debug('Failed to resolve git status for /status panel', { error });
        }
        props.addToChatQueue(_jsx(Status, { provider: props.currentProvider, model: props.currentModel, theme: props.currentTheme, updateInfo: props.updateInfo, mcpServersStatus: props.mcpServersStatus, lspServersStatus: props.lspServersStatus, preferencesLoaded: props.preferencesLoaded, customCommandsCount: props.customCommandsCount, contextUsage: contextUsage, autoCompactInfo: autoCompactInfo, gitStatus: gitStatus }, generateKey('status')));
    }, [
        props.client,
        props.currentProvider,
        props.currentModel,
        props.currentTheme,
        props.updateInfo,
        props.mcpServersStatus,
        props.lspServersStatus,
        props.preferencesLoaded,
        props.customCommandsCount,
        props.messages,
        props.getMessageTokens,
        props.addToChatQueue,
        logger,
        props,
    ]);
    // Checkpoint select handler
    const handleCheckpointSelect = React.useCallback(async (checkpointName, createBackup) => {
        try {
            const manager = new CheckpointManager();
            if (createBackup) {
                try {
                    await manager.saveCheckpoint(`backup-${new Date().toISOString().replace(/[:.]/g, '-')}`, props.messages, props.currentProvider, props.currentModel);
                }
                catch (error) {
                    props.addToChatQueue(_jsx(WarningMessage, { message: `Warning: Failed to create backup: ${formatError(error)}`, hideBox: true }, generateKey('backup-warning')));
                }
            }
            const checkpointData = await manager.loadCheckpoint(checkpointName, {
                validateIntegrity: true,
            });
            await manager.restoreFiles(checkpointData);
            props.addToChatQueue(_jsx(SuccessMessage, { message: `✓ Checkpoint '${checkpointName}' restored successfully`, hideBox: true }, generateKey('restore-success')));
        }
        catch (error) {
            props.addToChatQueue(_jsx(ErrorMessage, { message: `Failed to restore checkpoint: ${formatError(error)}`, hideBox: true }, generateKey('restore-error')));
        }
        finally {
            props.setActiveMode(null);
            props.setCheckpointLoadData(null);
        }
    }, [
        props.messages,
        props.currentProvider,
        props.currentModel,
        props.setActiveMode,
        props.setCheckpointLoadData,
        props.addToChatQueue,
        props,
    ]);
    // Checkpoint cancel handler
    const handleCheckpointCancel = React.useCallback(() => {
        props.setActiveMode(null);
        props.setCheckpointLoadData(null);
    }, [props.setActiveMode, props.setCheckpointLoadData, props]);
    // Enter checkpoint load mode handler
    const enterCheckpointLoadMode = React.useCallback((checkpoints, currentMessageCount) => {
        props.setCheckpointLoadData({ checkpoints, currentMessageCount });
        props.setActiveMode('checkpointLoad');
    }, [props.setCheckpointLoadData, props.setActiveMode, props]);
    // Enter session selector mode (for /resume with no args)
    const enterSessionSelectorMode = React.useCallback((showAll) => {
        props.setShowAllSessions(showAll ?? false);
        props.setActiveMode('sessionSelector');
    }, [props.setShowAllSessions, props.setActiveMode, props]);
    // Load and apply a session (messages, provider, model)
    const applySession = React.useCallback((session) => {
        props.updateMessages(session.messages);
        props.setCurrentProvider(session.provider);
        props.setCurrentModel(session.model);
        props.setCurrentSessionId(session.id);
        setKeyGeneratorSessionId(session.id);
        // Replay the persisted conversation into scrollback so the user can see
        // what they resumed (prompts, assistant replies, tool activity) instead
        // of an empty screen with only a success line.
        for (const component of buildSessionHistoryComponents(session.messages, session.model)) {
            props.addToChatQueue(component);
        }
        props.addToChatQueue(_jsx(SuccessMessage, { message: `Resumed session: ${session.title}`, hideBox: true }, generateKey('resume-success')));
        props.setActiveMode(null);
    }, [
        props.updateMessages,
        props.setCurrentProvider,
        props.setCurrentModel,
        props.setCurrentSessionId,
        props.setActiveMode,
        props.addToChatQueue,
        props,
    ]);
    const handleSessionSelect = React.useCallback(async (sessionId) => {
        try {
            const session = await sessionManager.loadSession(sessionId);
            if (session) {
                applySession(session);
            }
            else {
                props.addToChatQueue(_jsx(ErrorMessage, { message: "Session not found", hideBox: true }, generateKey('resume-error')));
                props.setActiveMode(null);
            }
        }
        catch (error) {
            props.addToChatQueue(_jsx(ErrorMessage, { message: `Failed to load session: ${formatError(error)}`, hideBox: true }, generateKey('resume-error')));
            props.setActiveMode(null);
        }
    }, [applySession, props.addToChatQueue, props.setActiveMode, props]);
    const handleSessionCancel = React.useCallback(() => {
        props.setActiveMode(null);
    }, [props.setActiveMode, props]);
    // Message submit handler
    const handleMessageSubmit = React.useCallback(async (message, displayValue, images) => {
        // Reset conversation completion flag when starting a new message
        props.setIsConversationComplete(false);
        // Extract command args for slash commands (used by /rename etc.).
        // The VS Code editor pill is appended at the end of the message
        // (\n\n[@…]<!--vscode-context-->…<!--/vscode-context-->); strip it
        // so it doesn't leak into the parsed args.
        const commandArgs = message.startsWith('/')
            ? message
                .replace(/\n\n\[@[^\]]+\]<!--vscode-context-->[\s\S]*?<!--\/vscode-context-->\s*$/, '')
                .slice(1)
                .trim()
                .split(/\s+/)
                .slice(1)
            : undefined;
        await handleMessageSubmission(message, {
            customCommandCache: props.customCommandCache,
            customCommandLoader: props.customCommandLoader,
            customCommandExecutor: props.customCommandExecutor,
            onClearMessages: clearMessages,
            onRenameSession: props.setSessionName,
            commandArgs,
            onEnterModelSelectionMode: props.enterModelSelectionMode,
            onEnterModelDatabaseMode: props.enterModelDatabaseMode,
            onEnterConfigWizardMode: props.enterConfigWizardMode,
            onEnterSettingsMode: props.enterSettingsMode,
            onEnterMcpWizardMode: props.enterMcpWizardMode,
            onEnterExplorerMode: props.enterExplorerMode,
            onEnterIdeSelectionMode: props.enterIdeSelectionMode,
            onEnterTune: props.enterTune,
            onEnterCheckpointLoadMode: enterCheckpointLoadMode,
            onEnterSessionSelectorMode: enterSessionSelectorMode,
            onResumeSession: session => applySession(session),
            onShowStatus: handleShowStatus,
            onHandleChatMessage: props.handleChatMessage,
            onAddToChatQueue: props.addToChatQueue,
            setLiveComponent: props.setLiveComponent,
            setIsToolExecuting: props.setIsToolExecuting,
            onCommandComplete: () => props.setIsConversationComplete(true),
            setMessages: props.updateMessages,
            messages: props.messages,
            provider: props.currentProvider,
            providerConfig: props.currentProviderConfig,
            client: props.client,
            model: props.currentModel,
            theme: props.currentTheme,
            updateInfo: props.updateInfo,
            getMessageTokens: props.getMessageTokens,
            tune: props.tune,
            developmentMode: props.developmentMode,
        }, displayValue, images);
    }, [
        props.setIsConversationComplete,
        props.customCommandCache,
        props.customCommandLoader,
        props.customCommandExecutor,
        props.enterModelSelectionMode,
        props.enterModelDatabaseMode,
        props.enterConfigWizardMode,
        props.enterSettingsMode,
        props.enterMcpWizardMode,
        props.enterExplorerMode,
        props.enterIdeSelectionMode,
        props.enterTune,
        props.handleChatMessage,
        props.addToChatQueue,
        props.setLiveComponent,
        props.setIsToolExecuting,
        props.updateMessages,
        props.messages,
        props.currentProvider,
        props.currentProviderConfig,
        props.currentModel,
        props.currentTheme,
        props.updateInfo,
        props.getMessageTokens,
        props.tune,
        props.developmentMode,
        clearMessages,
        enterCheckpointLoadMode,
        handleShowStatus,
        applySession,
        enterSessionSelectorMode,
        props,
    ]);
    return {
        clearMessages,
        handleCancel,
        handleToggleDevelopmentMode,
        handleShowStatus,
        handleCheckpointSelect,
        handleCheckpointCancel,
        enterCheckpointLoadMode,
        enterSessionSelectorMode,
        handleSessionSelect,
        handleSessionCancel,
        handleMessageSubmit,
    };
}
//# sourceMappingURL=useAppHandlers.js.map