import { jsx as _jsx } from "react/jsx-runtime";
/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import React from 'react';
import { Box, Text } from 'ink';
import { DiffRenderer } from './DiffRenderer.js';
import { MarkdownDisplay } from '../../utils/MarkdownDisplay.js';
import { AnsiOutputText, AnsiLineText } from '../AnsiOutput.js';
import { MaxSizedBox } from '../shared/MaxSizedBox.js';
import { theme } from '../../semantic-colors.js';
import { isSubagentProgress, } from '@google/gemini-cli-core';
import { useUIState } from '../../contexts/UIStateContext.js';
import { tryParseJSON } from '../../../utils/jsonoutput.js';
import { useAlternateBuffer } from '../../hooks/useAlternateBuffer.js';
import { Scrollable } from '../shared/Scrollable.js';
import { ScrollableList } from '../shared/ScrollableList.js';
import { SCROLL_TO_ITEM_END } from '../shared/VirtualizedList.js';
import { ACTIVE_SHELL_MAX_LINES } from '../../constants.js';
import { calculateToolContentMaxLines } from '../../utils/toolLayoutUtils.js';
import { SubagentProgressDisplay } from './SubagentProgressDisplay.js';
// Large threshold to ensure we don't cause performance issues for very large
// outputs that will get truncated further MaxSizedBox anyway.
const MAXIMUM_RESULT_DISPLAY_CHARACTERS = 20000;
export const ToolResultDisplay = ({ resultDisplay, availableTerminalHeight, terminalWidth, renderOutputAsMarkdown = true, maxLines, hasFocus = false, }) => {
    const { renderMarkdown } = useUIState();
    const isAlternateBuffer = useAlternateBuffer();
    const availableHeight = calculateToolContentMaxLines({
        availableTerminalHeight,
        isAlternateBuffer,
        maxLinesLimit: maxLines,
    });
    const combinedPaddingAndBorderWidth = 4;
    const childWidth = terminalWidth - combinedPaddingAndBorderWidth;
    const keyExtractor = React.useCallback((_, index) => index.toString(), []);
    const renderVirtualizedAnsiLine = React.useCallback(({ item }) => (_jsx(Box, { height: 1, overflow: "hidden", children: _jsx(AnsiLineText, { line: item }) })), []);
    const { truncatedResultDisplay, hiddenLinesCount } = React.useMemo(() => {
        let hiddenLines = 0;
        // Only truncate string output if not in alternate buffer mode to ensure
        // we can scroll through the full output.
        if (typeof resultDisplay === 'string' && !isAlternateBuffer) {
            let text = resultDisplay;
            if (text.length > MAXIMUM_RESULT_DISPLAY_CHARACTERS) {
                text = '...' + text.slice(-MAXIMUM_RESULT_DISPLAY_CHARACTERS);
            }
            if (maxLines) {
                const hasTrailingNewline = text.endsWith('\n');
                const contentText = hasTrailingNewline ? text.slice(0, -1) : text;
                const lines = contentText.split('\n');
                if (lines.length > maxLines) {
                    // We will have a label from MaxSizedBox. Reserve space for it.
                    const targetLines = Math.max(1, maxLines - 1);
                    hiddenLines = lines.length - targetLines;
                    text =
                        lines.slice(-targetLines).join('\n') +
                            (hasTrailingNewline ? '\n' : '');
                }
            }
            return { truncatedResultDisplay: text, hiddenLinesCount: hiddenLines };
        }
        if (Array.isArray(resultDisplay) && !isAlternateBuffer && maxLines) {
            if (resultDisplay.length > maxLines) {
                // We will have a label from MaxSizedBox. Reserve space for it.
                const targetLines = Math.max(1, maxLines - 1);
                return {
                    truncatedResultDisplay: resultDisplay.slice(-targetLines),
                    hiddenLinesCount: resultDisplay.length - targetLines,
                };
            }
        }
        return { truncatedResultDisplay: resultDisplay, hiddenLinesCount: 0 };
    }, [resultDisplay, isAlternateBuffer, maxLines]);
    if (!truncatedResultDisplay)
        return null;
    // 1. Early return for background tools (Todos)
    if (typeof truncatedResultDisplay === 'object' &&
        'todos' in truncatedResultDisplay) {
        // display nothing, as the TodoTray will handle rendering todos
        return null;
    }
    // 2. High-performance path: Virtualized ANSI in interactive mode
    if (isAlternateBuffer && Array.isArray(truncatedResultDisplay)) {
        // If availableHeight is undefined, fallback to a safe default to prevents infinite loop
        // where Container grows -> List renders more -> Container grows.
        const limit = maxLines ?? availableHeight ?? ACTIVE_SHELL_MAX_LINES;
        const listHeight = Math.min(
        // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
        truncatedResultDisplay.length, limit);
        return (_jsx(Box, { width: childWidth, flexDirection: "column", maxHeight: listHeight, children: _jsx(ScrollableList, { width: childWidth, 
                // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
                data: truncatedResultDisplay, renderItem: renderVirtualizedAnsiLine, estimatedItemHeight: () => 1, keyExtractor: keyExtractor, initialScrollIndex: SCROLL_TO_ITEM_END, hasFocus: hasFocus }) }));
    }
    // 3. Compute content node for non-virtualized paths
    // Check if string content is valid JSON and pretty-print it
    const prettyJSON = typeof truncatedResultDisplay === 'string'
        ? tryParseJSON(truncatedResultDisplay)
        : null;
    const formattedJSON = prettyJSON ? JSON.stringify(prettyJSON, null, 2) : null;
    let content;
    if (formattedJSON) {
        // Render pretty-printed JSON
        content = (_jsx(Text, { wrap: "wrap", color: theme.text.primary, children: formattedJSON }));
    }
    else if (isSubagentProgress(truncatedResultDisplay)) {
        content = _jsx(SubagentProgressDisplay, { progress: truncatedResultDisplay });
    }
    else if (typeof truncatedResultDisplay === 'string' &&
        renderOutputAsMarkdown) {
        content = (_jsx(MarkdownDisplay, { text: truncatedResultDisplay, terminalWidth: childWidth, renderMarkdown: renderMarkdown, isPending: false }));
    }
    else if (typeof truncatedResultDisplay === 'string' &&
        !renderOutputAsMarkdown) {
        content = (_jsx(Text, { wrap: "wrap", color: theme.text.primary, children: truncatedResultDisplay }));
    }
    else if (typeof truncatedResultDisplay === 'object' &&
        'fileDiff' in truncatedResultDisplay) {
        content = (_jsx(DiffRenderer
        // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
        , { 
            // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
            diffContent: truncatedResultDisplay.fileDiff, 
            // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
            filename: truncatedResultDisplay.fileName, availableTerminalHeight: availableHeight, terminalWidth: childWidth }));
    }
    else {
        const shouldDisableTruncation = isAlternateBuffer ||
            (availableTerminalHeight === undefined && maxLines === undefined);
        content = (_jsx(AnsiOutputText
        // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
        , { 
            // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
            data: truncatedResultDisplay, availableTerminalHeight: isAlternateBuffer ? undefined : availableHeight, width: childWidth, maxLines: isAlternateBuffer ? undefined : maxLines, disableTruncation: shouldDisableTruncation }));
    }
    // 4. Final render based on session mode
    if (isAlternateBuffer) {
        return (_jsx(Scrollable, { width: childWidth, maxHeight: maxLines ?? availableHeight, hasFocus: hasFocus, scrollToBottom: true, children: content }));
    }
    return (_jsx(Box, { width: childWidth, flexDirection: "column", children: _jsx(MaxSizedBox, { maxHeight: availableHeight, maxWidth: childWidth, additionalHiddenLinesCount: hiddenLinesCount, children: content }) }));
};
//# sourceMappingURL=ToolResultDisplay.js.map