import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
/**
 * @license
 * Copyright 2025 Vybestack LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { useCallback, useEffect, useState, useRef } from 'react';
import { Box, Text } from 'ink';
import { theme } from '../semantic-colors.js';
import { Colors } from '../colors.js';
import { SuggestionsDisplay } from './SuggestionsDisplay.js';
import { useInputHistory } from '../hooks/useInputHistory.js';
import { logicalPosToOffset } from './shared/text-buffer.js';
import { cpSlice, cpLen, getCachedStringWidth, toCodePoints, } from '../utils/textUtils.js';
import chalk from 'chalk';
import { useShellHistory } from '../hooks/useShellHistory.js';
import { useReverseSearchCompletion } from '../hooks/useReverseSearchCompletion.js';
import { useCommandCompletion } from '../hooks/useCommandCompletion.js';
import { useShellPathCompletion } from '../hooks/useShellPathCompletion.js';
import { useKeypress } from '../hooks/useKeypress.js';
import { keyMatchers, Command } from '../keyMatchers.js';
import { StreamingState } from '../types.js';
import { isAutoExecutableCommand, isSlashCommand, } from '../utils/commandUtils.js';
import { parseInputForHighlighting, buildSegmentsForVisualSlice, } from '../utils/highlight.js';
import { clipboardHasImage, saveClipboardImage, cleanupOldClipboardImages, } from '../utils/clipboardUtils.js';
import * as path from 'path';
import { SCREEN_READER_USER_PREFIX } from '../textConstants.js';
import { secureInputHandler } from '../utils/secureInputHandler.js';
import { useMouse } from '../hooks/useMouse.js';
import clipboardy from 'clipboardy';
const LARGE_PASTE_LINE_THRESHOLD = 4;
const LARGE_PASTE_CHAR_THRESHOLD = 1000;
const formatLargePastePlaceholder = (lines, chars, id) => {
    const idSuffix = ` #${id}`;
    if (lines > 1) {
        const label = lines === 1 ? 'line' : 'lines';
        return `[${lines} ${label} pasted${idSuffix}]`;
    }
    const charLabel = chars === 1 ? 'character' : 'characters';
    return `[${chars} ${charLabel} pasted${idSuffix}]`;
};
// The input content, input container, and input suggestions list may have different widths
export const calculatePromptWidths = (terminalWidth) => {
    const widthFraction = 0.9;
    const FRAME_PADDING_AND_BORDER = 4; // Border (2) + padding (2)
    const PROMPT_PREFIX_WIDTH = 2; // '> ' or '! '
    const MIN_CONTENT_WIDTH = 2;
    const innerContentWidth = Math.floor(terminalWidth * widthFraction) -
        FRAME_PADDING_AND_BORDER -
        PROMPT_PREFIX_WIDTH;
    const inputWidth = Math.max(MIN_CONTENT_WIDTH, innerContentWidth);
    const FRAME_OVERHEAD = FRAME_PADDING_AND_BORDER + PROMPT_PREFIX_WIDTH;
    const containerWidth = inputWidth + FRAME_OVERHEAD;
    const suggestionsWidth = Math.max(20, Math.floor(terminalWidth * 1.0));
    return {
        inputWidth,
        containerWidth,
        suggestionsWidth,
        frameOverhead: FRAME_OVERHEAD,
    };
};
export const InputPrompt = ({ buffer, onSubmit, userMessages, onClearScreen, config, slashCommands, commandContext, placeholder = '  Type your message or @path/to/file', focus = true, inputWidth, suggestionsWidth, shellModeActive, setShellModeActive, onEscapePromptChange, onSuggestionsVisibilityChange, suggestionsPosition = 'below', vimHandleInput, setQueueErrorMessage, streamingState, isEmbeddedShellFocused, }) => {
    const [justNavigatedHistory, setJustNavigatedHistory] = useState(false);
    const escPressCount = useRef(0);
    const [showEscapePrompt, setShowEscapePrompt] = useState(false);
    const escapeTimerRef = useRef(null);
    const pendingLargePastesRef = useRef(new Map());
    const [reverseSearchActive, setReverseSearchActive] = useState(false);
    const [textBeforeReverseSearch, setTextBeforeReverseSearch] = useState('');
    const [cursorPosition, setCursorPosition] = useState([
        0, 0,
    ]);
    const shellHistory = useShellHistory(config.getProjectRoot(), config.storage);
    const historyData = shellHistory.history;
    const completion = useCommandCompletion(buffer, config.getTargetDir(), slashCommands, commandContext, reverseSearchActive, shellModeActive, config);
    const reverseSearchCompletion = useReverseSearchCompletion(buffer, historyData, reverseSearchActive);
    const shellPathCompletion = useShellPathCompletion(buffer, config.getTargetDir(), shellModeActive, reverseSearchActive);
    const resetCompletionState = completion.resetCompletionState;
    const resetReverseSearchCompletionState = reverseSearchCompletion.resetCompletionState;
    useEffect(() => {
        onSuggestionsVisibilityChange?.(completion.showSuggestions ||
            reverseSearchActive ||
            shellPathCompletion.showSuggestions);
    }, [
        completion.showSuggestions,
        reverseSearchActive,
        shellPathCompletion.showSuggestions,
        onSuggestionsVisibilityChange,
    ]);
    const resetEscapeState = useCallback(() => {
        if (escapeTimerRef.current) {
            clearTimeout(escapeTimerRef.current);
            escapeTimerRef.current = null;
        }
        escPressCount.current = 0;
        setShowEscapePrompt(false);
    }, []);
    // Notify parent component about escape prompt state changes
    useEffect(() => {
        if (onEscapePromptChange) {
            onEscapePromptChange(showEscapePrompt);
        }
    }, [showEscapePrompt, onEscapePromptChange]);
    // Clear escape prompt timer on unmount
    useEffect(() => () => {
        if (escapeTimerRef.current) {
            clearTimeout(escapeTimerRef.current);
        }
    }, []);
    const nextPlaceholderIdRef = useRef(1);
    const handleSubmitAndClear = useCallback((submittedValue) => {
        let actualValue = submittedValue;
        const pendingPastes = pendingLargePastesRef.current;
        if (pendingPastes.size > 0) {
            pendingPastes.forEach((actualContent, placeholderLabel) => {
                if (actualValue.includes(placeholderLabel)) {
                    actualValue = actualValue
                        .split(placeholderLabel)
                        .join(actualContent);
                }
            });
        }
        if (shellModeActive) {
            shellHistory.addCommandToHistory(actualValue);
        }
        // Clear the buffer *before* calling onSubmit to prevent potential re-submission
        // if onSubmit triggers a re-render while the buffer still holds the old value.
        buffer.setText('');
        pendingLargePastesRef.current = new Map();
        onSubmit(actualValue);
        resetCompletionState();
        resetReverseSearchCompletionState();
    }, [
        onSubmit,
        buffer,
        resetCompletionState,
        shellModeActive,
        shellHistory,
        resetReverseSearchCompletionState,
    ]);
    const handleSubmit = useCallback((submittedValue) => {
        const trimmedMessage = submittedValue.trim();
        const isSlash = isSlashCommand(trimmedMessage);
        const isShell = shellModeActive;
        if ((isSlash || isShell) &&
            streamingState === StreamingState.Responding) {
            setQueueErrorMessage?.(`${isShell ? 'Shell' : 'Slash'} commands cannot be queued`);
            return;
        }
        handleSubmitAndClear(trimmedMessage);
    }, [
        handleSubmitAndClear,
        shellModeActive,
        streamingState,
        setQueueErrorMessage,
    ]);
    const customSetTextAndResetCompletionSignal = useCallback((newText) => {
        buffer.setText(newText);
        setJustNavigatedHistory(true);
    }, [buffer, setJustNavigatedHistory]);
    const inputHistory = useInputHistory({
        userMessages,
        onSubmit: handleSubmitAndClear,
        isActive: (!completion.showSuggestions || completion.suggestions.length === 1) &&
            !shellModeActive,
        currentQuery: buffer.text,
        onChange: customSetTextAndResetCompletionSignal,
    });
    // Effect to reset completion if history navigation just occurred and set the text
    useEffect(() => {
        if (justNavigatedHistory) {
            resetCompletionState();
            resetReverseSearchCompletionState();
            setJustNavigatedHistory(false);
        }
    }, [
        justNavigatedHistory,
        buffer.text,
        resetCompletionState,
        setJustNavigatedHistory,
        resetReverseSearchCompletionState,
    ]);
    useEffect(() => {
        const pendingPastes = pendingLargePastesRef.current;
        if (pendingPastes.size === 0) {
            return;
        }
        const filtered = Array.from(pendingPastes.entries()).filter(([placeholderLabel]) => buffer.text.includes(placeholderLabel));
        if (filtered.length !== pendingPastes.size) {
            pendingLargePastesRef.current = new Map(filtered);
        }
    }, [buffer.text]);
    // Handle clipboard pasting with Ctrl+V or right-click
    const handleClipboardPaste = useCallback(async () => {
        try {
            if (await clipboardHasImage()) {
                const imagePath = await saveClipboardImage(config.getTargetDir());
                if (imagePath) {
                    // Clean up old images
                    cleanupOldClipboardImages(config.getTargetDir()).catch(() => {
                        // Ignore cleanup errors
                    });
                    // Get relative path from current directory
                    const relativePath = path.relative(config.getTargetDir(), imagePath);
                    // Insert @path reference at cursor position
                    const insertText = `@${relativePath}`;
                    const currentText = buffer.text;
                    const [row, col] = buffer.cursor;
                    // Calculate offset from row/col
                    const offset = logicalPosToOffset(buffer.lines, row, col);
                    // Add spaces around the path if needed
                    let textToInsert = insertText;
                    const charBefore = offset > 0 ? currentText[offset - 1] : '';
                    const charAfter = offset < currentText.length ? currentText[offset] : '';
                    if (charBefore && charBefore !== ' ' && charBefore !== '\n') {
                        textToInsert = ' ' + textToInsert;
                    }
                    if (!charAfter || (charAfter !== ' ' && charAfter !== '\n')) {
                        textToInsert = textToInsert + ' ';
                    }
                    // Insert at cursor position
                    buffer.replaceRangeByOffset(offset, offset, textToInsert);
                }
                return;
            }
            // Fallback: try text paste
            try {
                const text = await clipboardy.read();
                if (text) {
                    const [row, col] = buffer.cursor;
                    const offset = logicalPosToOffset(buffer.lines, row, col);
                    buffer.replaceRangeByOffset(offset, offset, text);
                }
            }
            catch {
                // Silent no-op: clipboard read can fail on Wayland, SSH, headless, etc.
            }
        }
        catch (error) {
            console.error('Error handling clipboard paste:', error);
        }
    }, [buffer, config]);
    const handleInput = useCallback((key) => {
        /// We want to handle paste even when not focused to support drag and drop.
        if (!focus && !key.paste) {
            return;
        }
        if (isEmbeddedShellFocused) {
            if (keyMatchers[Command.TOGGLE_SHELL_INPUT_FOCUS](key)) {
                return;
            }
            return;
        }
        if (key.paste) {
            const sanitized = key.sequence.replace(/\r\n?/g, '\n');
            const charCount = cpLen(sanitized);
            const lineCount = sanitized.length === 0 ? 0 : sanitized.split('\n').length;
            if (lineCount >= LARGE_PASTE_LINE_THRESHOLD ||
                charCount >= LARGE_PASTE_CHAR_THRESHOLD) {
                const existingText = buffer.text;
                const cursorOffset = logicalPosToOffset(buffer.lines, buffer.cursor[0], buffer.cursor[1]);
                const before = existingText.slice(0, cursorOffset);
                const after = existingText.slice(cursorOffset);
                const placeholderId = nextPlaceholderIdRef.current++;
                const placeholderLabel = formatLargePastePlaceholder(lineCount, charCount, placeholderId);
                const placeholderText = `${before}${placeholderLabel}${after}`;
                buffer.setText(placeholderText);
                buffer.moveToOffset(cursorOffset + placeholderLabel.length);
                const nextPendingPastes = new Map(pendingLargePastesRef.current);
                nextPendingPastes.set(placeholderLabel, sanitized);
                pendingLargePastesRef.current = nextPendingPastes;
                return;
            }
            // Ensure we never accidentally interpret paste as regular input.
            buffer.handleInput({
                ...key,
                sequence: sanitized,
            });
            return;
        }
        if (vimHandleInput && vimHandleInput(key)) {
            return;
        }
        // Reset ESC count and hide prompt on any non-ESC key
        if (key.name !== 'escape') {
            if (escPressCount.current > 0 || showEscapePrompt) {
                resetEscapeState();
            }
        }
        if (key.sequence === '!' &&
            buffer.text === '' &&
            !completion.showSuggestions) {
            setShellModeActive(!shellModeActive);
            buffer.setText(''); // Clear the '!' from input
            return;
        }
        if (keyMatchers[Command.ESCAPE](key)) {
            if (reverseSearchActive) {
                setReverseSearchActive(false);
                reverseSearchCompletion.resetCompletionState();
                buffer.setText(textBeforeReverseSearch);
                const offset = logicalPosToOffset(buffer.lines, cursorPosition[0], cursorPosition[1]);
                buffer.moveToOffset(offset);
                return;
            }
            if (shellModeActive && shellPathCompletion.showSuggestions) {
                shellPathCompletion.resetCompletionState();
                resetEscapeState();
                return;
            }
            if (shellModeActive) {
                setShellModeActive(false);
                resetEscapeState();
                return;
            }
            if (completion.showSuggestions) {
                completion.resetCompletionState();
                resetEscapeState();
                return;
            }
            // Handle double ESC for clearing input
            if (escPressCount.current === 0) {
                if (buffer.text === '') {
                    return;
                }
                escPressCount.current = 1;
                setShowEscapePrompt(true);
                if (escapeTimerRef.current) {
                    clearTimeout(escapeTimerRef.current);
                }
                escapeTimerRef.current = setTimeout(() => {
                    resetEscapeState();
                }, 500);
            }
            else {
                // clear input and immediately reset state
                buffer.setText('');
                resetCompletionState();
                resetEscapeState();
            }
            return;
        }
        if (shellModeActive && keyMatchers[Command.REVERSE_SEARCH](key)) {
            setReverseSearchActive(true);
            setTextBeforeReverseSearch(buffer.text);
            setCursorPosition(buffer.cursor);
            return;
        }
        if (keyMatchers[Command.CLEAR_SCREEN](key)) {
            onClearScreen();
            return;
        }
        if (reverseSearchActive) {
            const { activeSuggestionIndex, navigateUp, navigateDown, showSuggestions, suggestions, } = reverseSearchCompletion;
            if (showSuggestions) {
                if (keyMatchers[Command.NAVIGATION_UP](key)) {
                    navigateUp();
                    return;
                }
                if (keyMatchers[Command.NAVIGATION_DOWN](key)) {
                    navigateDown();
                    return;
                }
                if (keyMatchers[Command.ACCEPT_SUGGESTION_REVERSE_SEARCH](key)) {
                    reverseSearchCompletion.handleAutocomplete(activeSuggestionIndex);
                    reverseSearchCompletion.resetCompletionState();
                    setReverseSearchActive(false);
                    return;
                }
            }
            if (keyMatchers[Command.SUBMIT_REVERSE_SEARCH](key)) {
                const textToSubmit = showSuggestions && activeSuggestionIndex > -1
                    ? suggestions[activeSuggestionIndex].value
                    : buffer.text;
                handleSubmitAndClear(textToSubmit);
                reverseSearchCompletion.resetCompletionState();
                setReverseSearchActive(false);
                return;
            }
            // Prevent up/down from falling through to regular history navigation
            if (keyMatchers[Command.NAVIGATION_UP](key) ||
                keyMatchers[Command.NAVIGATION_DOWN](key)) {
                return;
            }
        }
        // If the command is a perfect match, pressing enter should execute it.
        // We prioritize execution unless the user is explicitly selecting a different suggestion.
        if (completion.isPerfectMatch &&
            keyMatchers[Command.RETURN](key) &&
            (!completion.showSuggestions || completion.activeSuggestionIndex <= 0)) {
            handleSubmit(buffer.text);
            return;
        }
        if (completion.showSuggestions) {
            if (completion.suggestions.length > 1) {
                if (keyMatchers[Command.COMPLETION_UP](key)) {
                    completion.navigateUp();
                    return;
                }
                if (keyMatchers[Command.COMPLETION_DOWN](key)) {
                    completion.navigateDown();
                    return;
                }
            }
            if (keyMatchers[Command.ACCEPT_SUGGESTION](key)) {
                if (completion.suggestions.length > 0) {
                    const targetIndex = completion.activeSuggestionIndex === -1
                        ? 0 // Default to the first if none is active
                        : completion.activeSuggestionIndex;
                    if (targetIndex < completion.suggestions.length) {
                        const isEnterKey = key.name === 'return';
                        let handled = false;
                        if (isEnterKey && buffer.text.startsWith('/')) {
                            const isArgumentCompletion = completion.isArgumentCompletion;
                            const leafCommand = completion.leafCommand;
                            if (isArgumentCompletion &&
                                isAutoExecutableCommand(leafCommand)) {
                                const completedText = completion.handleAutocomplete(targetIndex);
                                if (completedText !== undefined) {
                                    handleSubmit(completedText.trim());
                                    return;
                                }
                                handled = true;
                            }
                            else if (!isArgumentCompletion) {
                                const command = completion.getCommandFromSuggestion(targetIndex);
                                if (isAutoExecutableCommand(command) &&
                                    !command?.completion) {
                                    const completedText = completion.handleAutocomplete(targetIndex);
                                    if (completedText !== undefined) {
                                        handleSubmit(completedText.trim());
                                        return;
                                    }
                                    handled = true;
                                }
                            }
                        }
                        if (!handled) {
                            completion.handleAutocomplete(targetIndex);
                        }
                    }
                }
                return;
            }
        }
        // Handle Tab key for ghost text acceptance
        if (key.name === 'tab' &&
            !completion.showSuggestions &&
            completion.promptCompletion.text) {
            completion.promptCompletion.accept();
            return;
        }
        if (!shellModeActive) {
            if (keyMatchers[Command.HISTORY_UP](key)) {
                inputHistory.navigateUp();
                return;
            }
            if (keyMatchers[Command.HISTORY_DOWN](key)) {
                inputHistory.navigateDown();
                return;
            }
            // Handle arrow-up/down for history on single-line or at edges
            if (keyMatchers[Command.NAVIGATION_UP](key) &&
                (buffer.allVisualLines.length === 1 ||
                    (buffer.visualCursor[0] === 0 && buffer.visualScrollRow === 0))) {
                inputHistory.navigateUp();
                return;
            }
            if (keyMatchers[Command.NAVIGATION_DOWN](key) &&
                (buffer.allVisualLines.length === 1 ||
                    buffer.visualCursor[0] === buffer.allVisualLines.length - 1)) {
                inputHistory.navigateDown();
                return;
            }
        }
        else if (shellPathCompletion.showSuggestions) {
            // Shell path completion — when suggestions are showing
            if (shellPathCompletion.suggestions.length > 1) {
                if (keyMatchers[Command.COMPLETION_UP](key)) {
                    shellPathCompletion.navigateUp();
                    return;
                }
                if (keyMatchers[Command.COMPLETION_DOWN](key)) {
                    shellPathCompletion.navigateDown();
                    return;
                }
            }
            if (key.name === 'tab') {
                const idx = shellPathCompletion.activeSuggestionIndex === -1
                    ? 0
                    : shellPathCompletion.activeSuggestionIndex;
                if (idx < shellPathCompletion.suggestions.length) {
                    shellPathCompletion.handleAutocomplete(idx);
                }
                return;
            }
        }
        else if (shellModeActive) {
            // Shell History Navigation — only when NO path suggestions showing
            if (keyMatchers[Command.NAVIGATION_UP](key)) {
                const prevCommand = shellHistory.getPreviousCommand();
                if (prevCommand !== null)
                    buffer.setText(prevCommand);
                return;
            }
            if (keyMatchers[Command.NAVIGATION_DOWN](key)) {
                const nextCommand = shellHistory.getNextCommand();
                if (nextCommand !== null)
                    buffer.setText(nextCommand);
                return;
            }
        }
        if (keyMatchers[Command.SUBMIT](key)) {
            if (buffer.text.trim()) {
                const [row, col] = buffer.cursor;
                const line = buffer.lines[row];
                const charBefore = col > 0 ? cpSlice(line, col - 1, col) : '';
                if (charBefore === '\\') {
                    buffer.backspace();
                    buffer.newline();
                }
                else {
                    handleSubmit(buffer.text);
                }
            }
            return;
        }
        // Newline insertion
        if (keyMatchers[Command.NEWLINE](key)) {
            buffer.newline();
            return;
        }
        // Ctrl+A (Home) / Ctrl+E (End)
        if (keyMatchers[Command.HOME](key)) {
            buffer.move('home');
            return;
        }
        if (keyMatchers[Command.END](key)) {
            buffer.move('end');
            return;
        }
        // Ctrl+C (Clear input)
        if (keyMatchers[Command.CLEAR_INPUT](key)) {
            if (buffer.text.length > 0) {
                buffer.setText('');
                resetCompletionState();
            }
            return;
        }
        // Kill line commands
        if (keyMatchers[Command.KILL_LINE_RIGHT](key)) {
            buffer.killLineRight();
            return;
        }
        if (keyMatchers[Command.KILL_LINE_LEFT](key)) {
            buffer.killLineLeft();
            return;
        }
        if (keyMatchers[Command.DELETE_WORD_BACKWARD](key)) {
            buffer.deleteWordLeft();
            return;
        }
        // External editor
        if (keyMatchers[Command.OPEN_EXTERNAL_EDITOR](key)) {
            // eslint-disable-next-line @typescript-eslint/no-floating-promises
            buffer.openInExternalEditor();
            return;
        }
        // Ctrl+V for clipboard paste
        if (keyMatchers[Command.PASTE_CLIPBOARD](key)) {
            // eslint-disable-next-line @typescript-eslint/no-floating-promises
            handleClipboardPaste();
            return;
        }
        // Fall back to the text buffer's default input handling for all other keys
        buffer.handleInput(key);
        // Clear ghost text when user types regular characters (not navigation/control keys)
        if (completion.promptCompletion.text &&
            key.sequence &&
            key.sequence.length === 1 &&
            !key.ctrl &&
            !key.meta) {
            completion.promptCompletion.clear();
        }
    }, [
        focus,
        buffer,
        completion,
        shellModeActive,
        setShellModeActive,
        onClearScreen,
        inputHistory,
        handleSubmitAndClear,
        handleSubmit,
        shellHistory,
        reverseSearchCompletion,
        shellPathCompletion,
        handleClipboardPaste,
        resetCompletionState,
        showEscapePrompt,
        resetEscapeState,
        vimHandleInput,
        reverseSearchActive,
        textBeforeReverseSearch,
        cursorPosition,
        isEmbeddedShellFocused,
    ]);
    useKeypress(handleInput, {
        isActive: true,
    });
    const handleMousePaste = useCallback((event) => {
        if (!focus || isEmbeddedShellFocused)
            return;
        if (event.name === 'right-release') {
            // eslint-disable-next-line @typescript-eslint/no-floating-promises
            handleClipboardPaste();
        }
    }, [focus, isEmbeddedShellFocused, handleClipboardPaste]);
    useMouse(handleMousePaste, { isActive: focus && !isEmbeddedShellFocused });
    const linesToRender = buffer.viewportVisualLines;
    const [cursorVisualRowAbsolute, cursorVisualColAbsolute] = buffer.visualCursor;
    const scrollVisualRow = buffer.visualScrollRow;
    const getGhostTextLines = useCallback(() => {
        if (!completion.promptCompletion.text ||
            !buffer.text ||
            !completion.promptCompletion.text.startsWith(buffer.text)) {
            return { inlineGhost: '', additionalLines: [] };
        }
        const ghostSuffix = completion.promptCompletion.text.slice(buffer.text.length);
        if (!ghostSuffix) {
            return { inlineGhost: '', additionalLines: [] };
        }
        const currentLogicalLine = buffer.lines[buffer.cursor[0]] || '';
        const cursorCol = buffer.cursor[1];
        const textBeforeCursor = cpSlice(currentLogicalLine, 0, cursorCol);
        const usedWidth = getCachedStringWidth(textBeforeCursor);
        const remainingWidth = Math.max(0, inputWidth - usedWidth);
        const ghostTextLinesRaw = ghostSuffix.split('\n');
        const firstLineRaw = ghostTextLinesRaw.shift() || '';
        let inlineGhost = '';
        let remainingFirstLine = '';
        if (getCachedStringWidth(firstLineRaw) <= remainingWidth) {
            inlineGhost = firstLineRaw;
        }
        else {
            const words = firstLineRaw.split(' ');
            let currentLine = '';
            let wordIdx = 0;
            for (const word of words) {
                const prospectiveLine = currentLine ? `${currentLine} ${word}` : word;
                if (getCachedStringWidth(prospectiveLine) > remainingWidth) {
                    break;
                }
                currentLine = prospectiveLine;
                wordIdx++;
            }
            inlineGhost = currentLine;
            if (words.length > wordIdx) {
                remainingFirstLine = words.slice(wordIdx).join(' ');
            }
        }
        const linesToWrap = [];
        if (remainingFirstLine) {
            linesToWrap.push(remainingFirstLine);
        }
        linesToWrap.push(...ghostTextLinesRaw);
        const remainingGhostText = linesToWrap.join('\n');
        const additionalLines = [];
        if (remainingGhostText) {
            const textLines = remainingGhostText.split('\n');
            for (const textLine of textLines) {
                const words = textLine.split(' ');
                let currentLine = '';
                for (const word of words) {
                    const prospectiveLine = currentLine ? `${currentLine} ${word}` : word;
                    const prospectiveWidth = getCachedStringWidth(prospectiveLine);
                    if (prospectiveWidth > inputWidth) {
                        if (currentLine) {
                            additionalLines.push(currentLine);
                        }
                        let wordToProcess = word;
                        while (getCachedStringWidth(wordToProcess) > inputWidth) {
                            let part = '';
                            const wordCP = toCodePoints(wordToProcess);
                            let partWidth = 0;
                            let splitIndex = 0;
                            for (let i = 0; i < wordCP.length; i++) {
                                const char = wordCP[i];
                                const charWidth = getCachedStringWidth(char);
                                if (partWidth + charWidth > inputWidth) {
                                    break;
                                }
                                part += char;
                                partWidth += charWidth;
                                splitIndex = i + 1;
                            }
                            additionalLines.push(part);
                            wordToProcess = cpSlice(wordToProcess, splitIndex);
                        }
                        currentLine = wordToProcess;
                    }
                    else {
                        currentLine = prospectiveLine;
                    }
                }
                if (currentLine) {
                    additionalLines.push(currentLine);
                }
            }
        }
        return { inlineGhost, additionalLines };
    }, [
        completion.promptCompletion.text,
        buffer.text,
        buffer.lines,
        buffer.cursor,
        inputWidth,
    ]);
    const { inlineGhost, additionalLines } = getGhostTextLines();
    const completionSuggestionsNode = completion.showSuggestions && !shellModeActive ? (_jsx(Box, { paddingRight: 2, children: _jsx(SuggestionsDisplay, { suggestions: completion.suggestions, activeIndex: completion.activeSuggestionIndex, isLoading: completion.isLoadingSuggestions, width: suggestionsWidth, scrollOffset: completion.visibleStartIndex, userInput: buffer.text, activeHint: completion.activeHint }) })) : null;
    const reverseSearchSuggestionsNode = reverseSearchActive ? (_jsx(Box, { paddingRight: 2, children: _jsx(SuggestionsDisplay, { suggestions: reverseSearchCompletion.suggestions, activeIndex: reverseSearchCompletion.activeSuggestionIndex, isLoading: reverseSearchCompletion.isLoadingSuggestions, width: suggestionsWidth, scrollOffset: reverseSearchCompletion.visibleStartIndex, userInput: buffer.text }) })) : null;
    const shellPathSuggestionsNode = shellPathCompletion.showSuggestions ? (_jsx(Box, { paddingRight: 2, children: _jsx(SuggestionsDisplay, { suggestions: shellPathCompletion.suggestions, activeIndex: shellPathCompletion.activeSuggestionIndex, isLoading: shellPathCompletion.isLoadingSuggestions, width: suggestionsWidth, scrollOffset: shellPathCompletion.visibleStartIndex, userInput: buffer.text }) })) : null;
    const suggestionsNode = completionSuggestionsNode ??
        shellPathSuggestionsNode ??
        reverseSearchSuggestionsNode;
    return (_jsxs(_Fragment, { children: [suggestionsPosition === 'above' && suggestionsNode, _jsxs(Box, { borderStyle: "round", borderColor: shellModeActive ? theme.status.warning : theme.border.focused, paddingX: 1, children: [_jsx(Text, { color: shellModeActive ? theme.status.warning : theme.text.accent, children: shellModeActive ? (reverseSearchActive ? (_jsxs(Text, { color: theme.text.link, "aria-label": SCREEN_READER_USER_PREFIX, children: ["(r:)", ' '] })) : ('! ')) : ('> ') }), _jsx(Box, { flexGrow: 1, flexDirection: "column", children: buffer.text.length === 0 && placeholder ? (focus ? (_jsxs(Text, { color: Colors.Foreground, children: [chalk.inverse(placeholder.slice(0, 1)), _jsx(Text, { color: Colors.DimComment, children: placeholder.slice(1) })] })) : (_jsx(Text, { color: Colors.DimComment, children: placeholder }))) : (linesToRender
                            .map((lineText, visualIdxInRenderedSet) => {
                            const absoluteVisualIdx = scrollVisualRow + visualIdxInRenderedSet;
                            const mapEntry = buffer.visualToLogicalMap[absoluteVisualIdx];
                            const cursorVisualRow = cursorVisualRowAbsolute - scrollVisualRow;
                            const isOnCursorLine = focus && visualIdxInRenderedSet === cursorVisualRow;
                            const renderedLine = [];
                            let charCount = 0;
                            let hasVisibleContent = false;
                            const [logicalLineIdx, logicalStartCol] = mapEntry ?? [0, 0];
                            const rawLogicalLine = mapEntry && buffer.lines[logicalLineIdx]
                                ? buffer.lines[logicalLineIdx]
                                : lineText;
                            // Apply live masking for /key and /toolkey commands.
                            // processInput returns same-length text with sensitive chars
                            // replaced by '*', so cursor positioning stays correct.
                            const logicalLine = logicalLineIdx === 0
                                ? secureInputHandler.processInput(rawLogicalLine)
                                : rawLogicalLine;
                            const tokens = parseInputForHighlighting(logicalLine, logicalLineIdx);
                            const visualStart = logicalStartCol;
                            const visualEnd = logicalStartCol + cpLen(lineText);
                            const segments = mapEntry
                                ? buildSegmentsForVisualSlice(tokens, visualStart, visualEnd)
                                : tokens;
                            segments.forEach((seg, segIdx) => {
                                const segLen = cpLen(seg.text);
                                if (segLen > 0) {
                                    hasVisibleContent = true;
                                }
                                let display = seg.text;
                                if (isOnCursorLine && segLen > 0) {
                                    const relativeVisualColForHighlight = cursorVisualColAbsolute;
                                    const segStart = charCount;
                                    const segEnd = segStart + segLen;
                                    if (relativeVisualColForHighlight >= segStart &&
                                        relativeVisualColForHighlight < segEnd) {
                                        const charToHighlight = cpSlice(seg.text, relativeVisualColForHighlight - segStart, relativeVisualColForHighlight - segStart + 1);
                                        const highlighted = chalk.inverse(charToHighlight);
                                        display =
                                            cpSlice(seg.text, 0, relativeVisualColForHighlight - segStart) +
                                                highlighted +
                                                cpSlice(seg.text, relativeVisualColForHighlight - segStart + 1);
                                    }
                                    charCount = segEnd;
                                }
                                else {
                                    charCount += segLen;
                                }
                                const color = seg.type === 'command' || seg.type === 'file'
                                    ? theme.text.accent
                                    : undefined;
                                if (segLen > 0) {
                                    renderedLine.push(_jsx(Text, { color: color, children: display }, `token-${segIdx}`));
                                }
                            });
                            const currentLineGhost = isOnCursorLine ? inlineGhost : '';
                            if (isOnCursorLine &&
                                cursorVisualColAbsolute === cpLen(lineText)) {
                                if (!currentLineGhost) {
                                    renderedLine.push(_jsx(Text, { color: Colors.Foreground, children: chalk.inverse(' ') }, "cursor-end"));
                                }
                            }
                            const showCursorBeforeGhost = focus &&
                                isOnCursorLine &&
                                cursorVisualColAbsolute === cpLen(lineText) &&
                                currentLineGhost;
                            if (!hasVisibleContent &&
                                !currentLineGhost &&
                                renderedLine.length === 0) {
                                renderedLine.push(_jsx(Text, { color: Colors.Foreground, children: ' ' }, "blank-placeholder"));
                            }
                            return (_jsxs(Text, { color: theme.text.accent, children: [renderedLine, showCursorBeforeGhost && chalk.inverse(' '), currentLineGhost && (_jsx(Text, { color: theme.text.secondary, children: currentLineGhost }))] }, `line-${visualIdxInRenderedSet}`));
                        })
                            .concat(additionalLines.map((ghostLine, index) => {
                            const padding = Math.max(0, inputWidth - getCachedStringWidth(ghostLine));
                            return (_jsxs(Text, { color: theme.text.secondary, children: [ghostLine, ' '.repeat(padding)] }, `ghost-line-${index}`));
                        }))) })] }), suggestionsPosition === 'below' && suggestionsNode] }));
};
//# sourceMappingURL=InputPrompt.js.map