/**
 * Enhanced Chat Input Component
 *
 * Improved input with:
 * - Command syntax highlighting
 * - History navigation with search (Ctrl+R)
 * - Keyword highlighting (think, megathink, ultrathink)
 * - File reference highlighting (@file.ts)
 * - Better multiline editing
 * - Keyboard shortcut hints
 */
import React, { useState, useMemo, useCallback } from "react";
import { Box, Text } from "ink";
import { useTheme } from "../context/theme-context.js";
/**
 * Tokenize input for syntax highlighting
 */
function tokenizeInput(text) {
    if (!text)
        return [];
    const tokens = [];
    let remaining = text;
    let _position = 0;
    // Patterns to match
    const patterns = [
        // Commands starting with /
        { regex: /^\/[a-zA-Z0-9_-]+/, type: "command", color: "cyan" },
        // Thinking keywords
        {
            regex: /^(think|megathink|ultrathink)\b/i,
            type: "thinking",
            color: "magenta",
        },
        // File references @path/to/file.ts
        { regex: /^@[\w./\\-]+/, type: "file_ref", color: "yellow" },
        // URLs
        { regex: /^https?:\/\/[^\s]+/, type: "url", color: "blue" },
        // Inline code `code`
        { regex: /^`[^`]+`/, type: "code", color: "green" },
        // Mentions @user
        { regex: /^@\w+/, type: "mention", color: "cyan" },
    ];
    while (remaining.length > 0) {
        let matched = false;
        for (const pattern of patterns) {
            const match = remaining.match(pattern.regex);
            if (match) {
                tokens.push({
                    type: pattern.type,
                    value: match[0],
                    color: pattern.color,
                });
                remaining = remaining.slice(match[0].length);
                _position += match[0].length;
                matched = true;
                break;
            }
        }
        if (!matched) {
            // Find next special character or take until next potential pattern
            let nextSpecial = remaining.length;
            for (const pattern of patterns) {
                const idx = remaining.slice(1).search(pattern.regex);
                if (idx !== -1 && idx + 1 < nextSpecial) {
                    nextSpecial = idx + 1;
                }
            }
            const textPart = remaining.slice(0, nextSpecial);
            if (textPart) {
                // Merge with previous text token if possible
                const lastToken = tokens[tokens.length - 1];
                if (lastToken && lastToken.type === "text") {
                    lastToken.value += textPart;
                }
                else {
                    tokens.push({ type: "text", value: textPart });
                }
            }
            remaining = remaining.slice(nextSpecial);
            _position += nextSpecial;
        }
    }
    return tokens;
}
/**
 * Render tokens with cursor
 */
function TokenRenderer({ tokens, cursorPosition, showCursor, }) {
    let charCount = 0;
    const elements = [];
    for (let i = 0; i < tokens.length; i++) {
        const token = tokens[i];
        const tokenStart = charCount;
        const tokenEnd = charCount + token.value.length;
        if (cursorPosition >= tokenStart && cursorPosition < tokenEnd && showCursor) {
            // Cursor is in this token
            const cursorOffset = cursorPosition - tokenStart;
            const before = token.value.slice(0, cursorOffset);
            const cursorChar = token.value.slice(cursorOffset, cursorOffset + 1) || " ";
            const after = token.value.slice(cursorOffset + 1);
            elements.push(React.createElement(React.Fragment, { key: i },
                React.createElement(Text, { color: token.color }, before),
                React.createElement(Text, { backgroundColor: "white", color: "black" }, cursorChar),
                React.createElement(Text, { color: token.color }, after)));
        }
        else {
            elements.push(React.createElement(Text, { key: i, color: token.color }, token.value));
        }
        charCount += token.value.length;
    }
    // Cursor at end
    if (cursorPosition >= charCount && showCursor) {
        elements.push(React.createElement(Text, { key: "cursor", backgroundColor: "white", color: "black" }, " "));
    }
    return React.createElement(React.Fragment, null, elements);
}
/**
 * History search component
 */
function HistorySearch({ history, query, selectedIndex, onSelect: _onSelect, onClose: _onClose, }) {
    const filteredHistory = useMemo(() => {
        if (!query)
            return history.slice(-10).reverse();
        return history
            .filter((item) => item.toLowerCase().includes(query.toLowerCase()))
            .slice(-10)
            .reverse();
    }, [history, query]);
    const clampedIndex = Math.min(selectedIndex, filteredHistory.length - 1);
    return (React.createElement(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", padding: 1, marginBottom: 1 },
        React.createElement(Box, { marginBottom: 1 },
            React.createElement(Text, { color: "yellow" }, "History Search (Ctrl+R): "),
            React.createElement(Text, null, query),
            React.createElement(Text, { backgroundColor: "white", color: "black" }, " ")),
        filteredHistory.length === 0 ? (React.createElement(Text, { dimColor: true }, "No matching history")) : (React.createElement(Box, { flexDirection: "column" }, filteredHistory.slice(0, 5).map((item, index) => (React.createElement(Box, { key: index },
            React.createElement(Text, { color: index === clampedIndex ? "cyan" : undefined }, index === clampedIndex ? "❯ " : "  "),
            React.createElement(Text, { color: index === clampedIndex ? "cyan" : undefined, dimColor: index !== clampedIndex }, item.length > 60 ? item.slice(0, 57) + "..." : item)))))),
        React.createElement(Box, { marginTop: 1 },
            React.createElement(Text, { dimColor: true }, "\u2191\u2193 navigate \u2022 Enter select \u2022 Esc cancel"))));
}
/**
 * Keyboard shortcuts hint bar
 */
function ShortcutsHint({ isMultiline }) {
    return (React.createElement(Box, { marginTop: 1 },
        React.createElement(Text, { dimColor: true },
            "Enter send \u2022 Shift+Enter newline \u2022 \u2191\u2193 history \u2022 Ctrl+R search",
            isMultiline && " • Ctrl+L clear")));
}
/**
 * Enhanced Chat Input Component
 */
export function EnhancedChatInput({ input, cursorPosition, isProcessing, isStreaming, history = [], onHistorySelect, showShortcuts = true, }) {
    const { colors } = useTheme();
    const [historySearchMode, setHistorySearchMode] = useState(false);
    const [historyQuery, setHistoryQuery] = useState("");
    const [historyIndex, _setHistoryIndex] = useState(0);
    // Tokenize input
    const tokens = useMemo(() => tokenizeInput(input), [input]);
    // Calculate cursor data for multiline
    const cursorData = useMemo(() => {
        const lines = input.split("\n");
        const isMultiline = lines.length > 1;
        let currentLineIndex = 0;
        let currentCharIndex = 0;
        let totalChars = 0;
        for (let i = 0; i < lines.length; i++) {
            if (totalChars + lines[i].length >= cursorPosition) {
                currentLineIndex = i;
                currentCharIndex = cursorPosition - totalChars;
                break;
            }
            totalChars += lines[i].length + 1;
        }
        return { lines, isMultiline, currentLineIndex, currentCharIndex };
    }, [input, cursorPosition]);
    const showCursor = !isProcessing && !isStreaming;
    const borderColor = isProcessing || isStreaming ? colors.borderBusy : colors.borderActive;
    const promptColor = colors.primary;
    // Handle history search input (managed separately from main input)
    // This is controlled by the parent component through keyboard handling
    // Placeholder
    const placeholderText = "Ask me anything... (try /help for commands)";
    const isPlaceholder = !input;
    // Multiline rendering
    if (cursorData.isMultiline) {
        return (React.createElement(Box, { flexDirection: "column" },
            historySearchMode && (React.createElement(HistorySearch, { history: history, query: historyQuery, selectedIndex: historyIndex, onSelect: (item) => {
                    onHistorySelect?.(item);
                    setHistorySearchMode(false);
                    setHistoryQuery("");
                }, onClose: () => {
                    setHistorySearchMode(false);
                    setHistoryQuery("");
                } })),
            React.createElement(Box, { borderStyle: "round", borderColor: borderColor, paddingY: 0, marginTop: 1, flexDirection: "column" }, cursorData.lines.map((line, index) => {
                const isCurrentLine = index === cursorData.currentLineIndex;
                const promptChar = index === 0 ? "❯" : "│";
                const lineTokens = tokenizeInput(line);
                // Calculate cursor position within this line
                let lineStartPos = 0;
                for (let i = 0; i < index; i++) {
                    lineStartPos += cursorData.lines[i].length + 1;
                }
                const lineCursorPos = cursorPosition - lineStartPos;
                return (React.createElement(Box, { key: index },
                    React.createElement(Text, { color: promptColor },
                        promptChar,
                        " "),
                    isCurrentLine ? (React.createElement(TokenRenderer, { tokens: lineTokens, cursorPosition: lineCursorPos, showCursor: showCursor })) : (React.createElement(TokenRenderer, { tokens: lineTokens, cursorPosition: -1, showCursor: false }))));
            })),
            showShortcuts && React.createElement(ShortcutsHint, { isMultiline: true })));
    }
    // Single line rendering
    return (React.createElement(Box, { flexDirection: "column" },
        historySearchMode && (React.createElement(HistorySearch, { history: history, query: historyQuery, selectedIndex: historyIndex, onSelect: (item) => {
                onHistorySelect?.(item);
                setHistorySearchMode(false);
                setHistoryQuery("");
            }, onClose: () => {
                setHistorySearchMode(false);
                setHistoryQuery("");
            } })),
        React.createElement(Box, { borderStyle: "round", borderColor: borderColor, paddingX: 1, paddingY: 0, marginTop: 1 },
            React.createElement(Box, null,
                React.createElement(Text, { color: promptColor }, "\u276F "),
                isPlaceholder ? (React.createElement(React.Fragment, null,
                    React.createElement(Text, { color: colors.textMuted, dimColor: true }, placeholderText),
                    showCursor && (React.createElement(Text, { backgroundColor: "white", color: "black" }, " ")))) : (React.createElement(TokenRenderer, { tokens: tokens, cursorPosition: cursorPosition, showCursor: showCursor })))),
        showShortcuts && React.createElement(ShortcutsHint, { isMultiline: false })));
}
/**
 * Hook for managing input history
 */
export function useInputHistory(maxSize = 100) {
    const [history, setHistory] = useState([]);
    const [historyIndex, setHistoryIndex] = useState(-1);
    const [savedInput, setSavedInput] = useState("");
    const addToHistory = useCallback((input) => {
        if (!input.trim())
            return;
        setHistory((prev) => {
            // Don't add duplicates of the last entry
            if (prev[prev.length - 1] === input)
                return prev;
            const newHistory = [...prev, input];
            if (newHistory.length > maxSize) {
                return newHistory.slice(-maxSize);
            }
            return newHistory;
        });
        setHistoryIndex(-1);
        setSavedInput("");
    }, [maxSize]);
    const navigateHistory = useCallback((direction, currentInput) => {
        if (history.length === 0)
            return null;
        let newIndex;
        if (direction === "up") {
            if (historyIndex === -1) {
                // Save current input before navigating
                setSavedInput(currentInput);
                newIndex = history.length - 1;
            }
            else if (historyIndex > 0) {
                newIndex = historyIndex - 1;
            }
            else {
                return null; // Already at oldest
            }
        }
        else {
            // down
            if (historyIndex === -1) {
                return null; // Already at newest
            }
            else if (historyIndex < history.length - 1) {
                newIndex = historyIndex + 1;
            }
            else {
                // Return to saved input
                setHistoryIndex(-1);
                return savedInput;
            }
        }
        setHistoryIndex(newIndex);
        return history[newIndex];
    }, [history, historyIndex, savedInput]);
    const searchHistory = useCallback((query) => {
        if (!query)
            return history.slice(-10);
        return history.filter((item) => item.toLowerCase().includes(query.toLowerCase()));
    }, [history]);
    const resetNavigation = useCallback(() => {
        setHistoryIndex(-1);
        setSavedInput("");
    }, []);
    return {
        history,
        addToHistory,
        navigateHistory,
        searchHistory,
        resetNavigation,
        historyIndex,
    };
}
export default EnhancedChatInput;
//# sourceMappingURL=EnhancedChatInput.js.map