import React, { useState, useEffect, useRef, useCallback } from "react";
import { Box, Text, useInput } from "ink";
import { useInputHandler } from "../../hooks/use-input-handler.js";
import { LoadingSpinner } from "./LoadingSpinner.js";
import { CommandSuggestions } from "./CommandSuggestions.js";
import { ModelSelection } from "./ModelSelection.js";
import { ChatHistory } from "./ChatHistory.js";
import { TabbedQuestion } from "./TabbedQuestion.js";
import { ChatInput } from "./ChatInput.js";
import { MCPStatus } from "./McpStatus.js";
import ConfirmationDialog from "./ConfirmationDialog.js";
import { ConfirmationService, } from "../../utils/confirmation-service.js";
import ApiKeyInput from "./ApiKeyInput.js";
import { renderColorBanner } from "../../utils/ascii-banner.js";
import { ThemeProvider, useTheme } from "../context/theme-context.js";
import { getErrorMessage } from "../../types/index.js";
import { MiniStatusBar } from "./StatusBar.js";
import { KeyboardHelp, useKeyboardHelp, KeyboardHelpButton } from "./KeyboardHelp.js";
import { ToastProvider } from "./ToastNotifications.js";
import { logger } from "../../utils/logger.js";
import { announceToScreenReader, useAccessibilitySettings, useKeyboardShortcuts, } from "../utils/accessibility.js";
// Main chat component that handles input when agent is available
function ChatInterfaceWithAgent({ agent, initialMessage, }) {
    const { colors, theme } = useTheme();
    const { settings } = useAccessibilitySettings();
    const [chatHistory, setChatHistory] = useState([]);
    const [isProcessing, setIsProcessing] = useState(false);
    const [processingTime, setProcessingTime] = useState(0);
    const [tokenCount, setTokenCount] = useState(0);
    const [isStreaming, setIsStreaming] = useState(false);
    const [confirmationOptions, setConfirmationOptions] = useState(null);
    const [pendingQuestion, setPendingQuestion] = useState(null);
    const [_sessionStartTime] = useState(new Date());
    const scrollRef = useRef(null);
    const processingStartTime = useRef(0);
    const confirmationService = ConfirmationService.getInstance();
    const keyboardHelp = useKeyboardHelp();
    // Handle keyboard shortcut for help overlay (?)
    useInput((input) => {
        if (input === '?' && !isProcessing && !confirmationOptions) {
            keyboardHelp.toggle();
        }
    });
    // Keyboard shortcuts with accessibility support
    useKeyboardShortcuts([
        {
            keys: ['ctrl', 'h'],
            description: 'Show help',
            handler: () => {
                // This would trigger help display
                announceToScreenReader('Opening help', 'polite');
            },
            enabled: !confirmationOptions && !isProcessing,
        },
        {
            keys: ['ctrl', '/'],
            description: 'Toggle accessibility settings',
            handler: () => {
                announceToScreenReader('Accessibility settings', 'polite');
            },
            enabled: !confirmationOptions,
        },
    ]);
    // Optimized update functions to avoid O(n²) array spreading on each streaming chunk
    // These use indexed updates instead of mapping the entire array
    const appendStreamingContent = useCallback((content) => {
        setChatHistory((prev) => {
            const lastIndex = prev.length - 1;
            const lastEntry = prev[lastIndex];
            if (lastEntry?.isStreaming) {
                // Create new array with only the last element changed
                const updated = [...prev];
                updated[lastIndex] = { ...lastEntry, content: lastEntry.content + content };
                return updated;
            }
            return prev;
        });
    }, []);
    const finalizeStreamingEntry = useCallback((updates) => {
        setChatHistory((prev) => {
            const lastIndex = prev.length - 1;
            const lastEntry = prev[lastIndex];
            if (lastEntry?.isStreaming) {
                const updated = [...prev];
                updated[lastIndex] = { ...lastEntry, isStreaming: false, ...updates };
                return updated;
            }
            return prev;
        });
    }, []);
    const updateToolCallEntry = useCallback((toolCallId, updates) => {
        setChatHistory((prev) => {
            const index = prev.findIndex((entry) => entry.type === "tool_call" && entry.toolCall?.id === toolCallId);
            if (index !== -1) {
                const updated = [...prev];
                updated[index] = { ...prev[index], ...updates };
                return updated;
            }
            return prev;
        });
    }, []);
    const { input, cursorPosition, showCommandSuggestions, selectedCommandIndex, showModelSelection, selectedModelIndex, commandSuggestions, availableModels, autoEditEnabled, } = useInputHandler({
        agent,
        chatHistory,
        setChatHistory,
        setIsProcessing,
        setIsStreaming,
        setTokenCount,
        setProcessingTime,
        processingStartTime,
        isProcessing,
        isStreaming,
        isConfirmationActive: !!confirmationOptions,
    });
    useEffect(() => {
        // Only clear console on non-Windows platforms or if not PowerShell
        // Windows PowerShell can have issues with console.clear() causing flickering
        const isWindows = process.platform === "win32";
        const isPowerShell = process.env.ComSpec?.toLowerCase().includes("powershell") ||
            process.env.PSModulePath !== undefined;
        if (!isWindows || !isPowerShell) {
            process.stdout.write('\x1b[2J\x1b[0f'); // ANSI escape code to clear screen
        }
        // Add top padding
        logger.info("    ");
        // Generate logo with MIT-licensed ascii-banner (replaces GPL cfonts)
        const logoOutput = renderColorBanner("CODE BUDDY", ["magenta", "cyan"]);
        // Add horizontal margin (2 spaces) to match Ink paddingX={2}
        const logoLines = logoOutput.split("\n");
        logoLines.forEach((line) => {
            if (line.trim()) {
                logger.info(" " + line); // Add 2 spaces for horizontal margin
            }
            else {
                logger.info(line); // Keep empty lines as-is
            }
        });
        logger.info(" "); // Spacing after logo
        setChatHistory([]);
        // Announce to screen readers
        if (settings.screenReader) {
            announceToScreenReader('Code Buddy started. Chat interface ready. Press Ctrl+H for help.', 'polite');
        }
    }, [settings.screenReader]);
    // Process initial message if provided (streaming for faster feedback)
    useEffect(() => {
        if (initialMessage && agent) {
            const userEntry = {
                type: "user",
                content: initialMessage,
                timestamp: new Date(),
            };
            setChatHistory([userEntry]);
            const processInitialMessage = async () => {
                setIsProcessing(true);
                setIsStreaming(true);
                try {
                    let streamingEntry = null;
                    for await (const chunk of agent.processUserMessageStream(initialMessage)) {
                        switch (chunk.type) {
                            case "reasoning":
                                if (chunk.reasoning) {
                                    // Handle reasoning/thinking content
                                    setChatHistory((prev) => {
                                        const last = prev[prev.length - 1];
                                        if (last?.type === 'reasoning' && last.isStreaming) {
                                            const updated = [...prev];
                                            updated[prev.length - 1] = { ...last, content: last.content + chunk.reasoning };
                                            return updated;
                                        }
                                        return [...prev, {
                                                type: 'reasoning',
                                                content: chunk.reasoning,
                                                timestamp: new Date(),
                                                isStreaming: true,
                                            }];
                                    });
                                }
                                break;
                            case "content":
                                if (chunk.content) {
                                    // Finalize any streaming reasoning entry
                                    setChatHistory((prev) => {
                                        const last = prev[prev.length - 1];
                                        if (last?.type === 'reasoning' && last.isStreaming) {
                                            const updated = [...prev];
                                            updated[prev.length - 1] = { ...last, isStreaming: false };
                                            return updated;
                                        }
                                        return prev;
                                    });
                                    if (!streamingEntry) {
                                        // First chunk - add new streaming entry
                                        const newStreamingEntry = {
                                            type: "assistant",
                                            content: chunk.content,
                                            timestamp: new Date(),
                                            isStreaming: true,
                                        };
                                        setChatHistory((prev) => [...prev, newStreamingEntry]);
                                        streamingEntry = newStreamingEntry;
                                    }
                                    else {
                                        // Subsequent chunks - use optimized append (avoids O(n²) mapping)
                                        appendStreamingContent(chunk.content);
                                    }
                                }
                                break;
                            case "token_count":
                                if (chunk.tokenCount !== undefined) {
                                    setTokenCount(chunk.tokenCount);
                                }
                                break;
                            case "tool_calls":
                                if (chunk.toolCalls) {
                                    // Finalize streaming entry with tool calls
                                    finalizeStreamingEntry({ toolCalls: chunk.toolCalls });
                                    streamingEntry = null;
                                    // Add individual tool call entries to show tools are being executed
                                    const toolCallEntries = chunk.toolCalls.map((toolCall) => ({
                                        type: "tool_call",
                                        content: "Executing...",
                                        timestamp: new Date(),
                                        toolCall: toolCall,
                                    }));
                                    setChatHistory((prev) => [...prev, ...toolCallEntries]);
                                }
                                break;
                            case "tool_stream":
                                if (chunk.toolStreamData) {
                                    const { toolCallId, toolName, delta } = chunk.toolStreamData;
                                    // Update the tool_call entry with streaming output
                                    setChatHistory((prev) => {
                                        const idx = prev.findIndex((e) => e.type === 'tool_call' && e.toolCall?.id === toolCallId);
                                        if (idx !== -1) {
                                            const updated = [...prev];
                                            const existing = updated[idx];
                                            updated[idx] = {
                                                ...existing,
                                                content: (existing.content === 'Executing...' ? '' : existing.content) + delta,
                                                isStreaming: true,
                                            };
                                            return updated;
                                        }
                                        return prev;
                                    });
                                }
                                break;
                            case "tool_result":
                                if (chunk.toolCall && chunk.toolResult) {
                                    // Finalize any streaming entry
                                    finalizeStreamingEntry();
                                    // Update the specific tool call entry using optimized update
                                    updateToolCallEntry(chunk.toolCall.id, {
                                        type: "tool_result",
                                        content: chunk.toolResult?.success
                                            ? chunk.toolResult?.output || "Success"
                                            : chunk.toolResult?.error || "Error occurred",
                                        toolResult: chunk.toolResult,
                                    });
                                    streamingEntry = null;
                                }
                                break;
                            case "plan_progress":
                                if (chunk.planProgress) {
                                    const { taskId, status, total, completed, message } = chunk.planProgress;
                                    const progressText = message || `Task ${taskId}: ${status} (${completed}/${total})`;
                                    setChatHistory((prev) => [...prev, {
                                            type: 'plan_progress',
                                            content: progressText,
                                            timestamp: new Date(),
                                        }]);
                                }
                                break;
                            case "ask_user":
                                if (chunk.askUser) {
                                    // Add question entry to chat history
                                    setChatHistory((prev) => [...prev, {
                                            type: 'assistant',
                                            content: chunk.askUser.question,
                                            timestamp: new Date(),
                                        }]);
                                    // Show tabbed question UI (the streaming loop will wait for resolution)
                                    const answer = await new Promise((resolve) => {
                                        setPendingQuestion({
                                            question: chunk.askUser.question,
                                            options: chunk.askUser.options,
                                            resolve,
                                        });
                                    });
                                    // Add user's answer to history
                                    setChatHistory((prev) => [...prev, {
                                            type: 'user',
                                            content: answer,
                                            timestamp: new Date(),
                                        }]);
                                    setPendingQuestion(null);
                                }
                                break;
                            case "done":
                                if (streamingEntry) {
                                    finalizeStreamingEntry();
                                }
                                setIsStreaming(false);
                                break;
                        }
                    }
                }
                catch (error) {
                    const errorMessage = getErrorMessage(error);
                    const errorEntry = {
                        type: "assistant",
                        content: `Error: ${errorMessage}`,
                        timestamp: new Date(),
                    };
                    setChatHistory((prev) => [...prev, errorEntry]);
                    setIsStreaming(false);
                    // Announce errors to screen readers
                    if (settings.screenReader) {
                        announceToScreenReader(`Error occurred: ${errorMessage}`, 'assertive');
                    }
                }
                setIsProcessing(false);
                processingStartTime.current = 0;
            };
            processInitialMessage();
        }
    }, [initialMessage, agent]);
    useEffect(() => {
        const handleConfirmationRequest = (options) => {
            setConfirmationOptions(options);
        };
        confirmationService.on("confirmation-requested", handleConfirmationRequest);
        return () => {
            confirmationService.off("confirmation-requested", handleConfirmationRequest);
        };
    }, [confirmationService]);
    useEffect(() => {
        if (!isProcessing && !isStreaming) {
            setProcessingTime(0);
            return;
        }
        if (processingStartTime.current === 0) {
            processingStartTime.current = Date.now();
        }
        const interval = setInterval(() => {
            setProcessingTime(Math.floor((Date.now() - processingStartTime.current) / 1000));
        }, 1000);
        return () => clearInterval(interval);
    }, [isProcessing, isStreaming]);
    const handleConfirmation = (dontAskAgain) => {
        confirmationService.confirmOperation(true, dontAskAgain);
        setConfirmationOptions(null);
        // Announce to screen readers
        if (settings.screenReader) {
            announceToScreenReader('Operation confirmed', 'polite');
        }
    };
    const handleRejection = (feedback) => {
        confirmationService.rejectOperation(feedback);
        setConfirmationOptions(null);
        // Reset processing states when operation is cancelled
        setIsProcessing(false);
        setIsStreaming(false);
        setTokenCount(0);
        setProcessingTime(0);
        processingStartTime.current = 0;
        // Announce to screen readers
        if (settings.screenReader) {
            announceToScreenReader('Operation cancelled', 'polite');
        }
    };
    return (React.createElement(Box, { flexDirection: "column", paddingX: 2 },
        chatHistory.length === 0 && !confirmationOptions && (React.createElement(Box, { flexDirection: "column", marginBottom: 2 },
            React.createElement(Text, { color: colors.primary, bold: true }, "Tips for getting started:"),
            React.createElement(Box, { marginTop: 1, flexDirection: "column" },
                React.createElement(Text, { color: colors.textMuted }, "1. Ask questions, edit files, or run commands."),
                React.createElement(Text, { color: colors.textMuted }, "2. Be specific for the best results."),
                React.createElement(Text, { color: colors.textMuted }, "3. Create CODEBUDDY.md files to customize your interactions with Code Buddy."),
                React.createElement(Text, { color: colors.textMuted }, "4. Press Shift+Tab to toggle auto-edit mode."),
                React.createElement(Text, { color: colors.textMuted }, "5. /help for more information."),
                React.createElement(Text, { color: colors.textMuted }, "6. /theme to change the theme, /avatar to change avatars.")),
            React.createElement(Box, { marginTop: 1 },
                React.createElement(KeyboardHelpButton, null)))),
        React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
            React.createElement(Text, { color: colors.textMuted }, "Type your request in natural language. Ctrl+C to clear, 'exit' to quit.")),
        React.createElement(Box, { flexDirection: "column", ref: scrollRef },
            React.createElement(ChatHistory, { entries: chatHistory, isConfirmationActive: !!confirmationOptions })),
        pendingQuestion && (React.createElement(TabbedQuestion, { question: pendingQuestion.question, options: pendingQuestion.options, onAnswer: (answer) => {
                pendingQuestion.resolve(answer);
            } })),
        confirmationOptions && (React.createElement(ConfirmationDialog, { operation: confirmationOptions.operation, filename: confirmationOptions.filename, showVSCodeOpen: confirmationOptions.showVSCodeOpen, content: confirmationOptions.content, onConfirm: handleConfirmation, onReject: handleRejection })),
        !confirmationOptions && (React.createElement(React.Fragment, null,
            React.createElement(LoadingSpinner, { isActive: isProcessing || isStreaming, processingTime: processingTime, tokenCount: tokenCount }),
            React.createElement(ChatInput, { input: input, cursorPosition: cursorPosition, isProcessing: isProcessing, isStreaming: isStreaming, mode: agent.getMode() }),
            React.createElement(Box, { flexDirection: "row", marginTop: 1, justifyContent: "space-between" },
                React.createElement(Box, { flexDirection: "row" },
                    React.createElement(Box, { marginRight: 2 },
                        React.createElement(Text, { color: colors.primary },
                            autoEditEnabled ? "▶" : "⏸",
                            " auto-edit:",
                            " ",
                            autoEditEnabled ? "on" : "off"),
                        React.createElement(Text, { color: colors.textMuted, dimColor: true },
                            " ",
                            "(shift + tab)")),
                    React.createElement(Box, { marginRight: 2 },
                        React.createElement(Text, { color: colors.secondary },
                            "\u25D0 ",
                            theme.name)),
                    React.createElement(MCPStatus, null)),
                React.createElement(Box, null,
                    React.createElement(MiniStatusBar, { tokenCount: tokenCount, modelName: agent.getCurrentModel(), mode: agent.getMode(), yolo: agent.isYoloModeEnabled() }))),
            React.createElement(CommandSuggestions, { suggestions: commandSuggestions, input: input, selectedIndex: selectedCommandIndex, isVisible: showCommandSuggestions }),
            React.createElement(ModelSelection, { models: availableModels, selectedIndex: selectedModelIndex, isVisible: showModelSelection, currentModel: agent.getCurrentModel() }))),
        React.createElement(KeyboardHelp, { isVisible: keyboardHelp.isVisible, onClose: keyboardHelp.hide })));
}
// Inner component that handles API key input or chat interface
function ChatInterfaceInner({ agent, initialMessage, }) {
    const [currentAgent, setCurrentAgent] = useState(agent || null);
    const handleApiKeySet = (newAgent) => {
        setCurrentAgent(newAgent);
    };
    if (!currentAgent) {
        return React.createElement(ApiKeyInput, { onApiKeySet: handleApiKeySet });
    }
    return (React.createElement(ChatInterfaceWithAgent, { agent: currentAgent, initialMessage: initialMessage }));
}
// Main component wrapped with ThemeProvider and ToastProvider
export default function ChatInterface({ agent, initialMessage, }) {
    return (React.createElement(ThemeProvider, null,
        React.createElement(ToastProvider, null,
            React.createElement(ChatInterfaceInner, { agent: agent, initialMessage: initialMessage }))));
}
//# sourceMappingURL=ChatInterface.js.map