import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import React, { useState, useEffect } from 'react';
import { Box, Text } from 'ink';
import { ToolCallStatus, mapCoreStatusToDisplayStatus } from '../../types.js';
import { GeminiRespondingSpinner } from '../GeminiRespondingSpinner.js';
import { SHELL_COMMAND_NAME, SHELL_NAME, TOOL_STATUS, SHELL_FOCUS_HINT_DELAY_MS, } from '../../constants.js';
import { theme } from '../../semantic-colors.js';
import { SHELL_TOOL_NAME, isCompletedAskUserTool, CoreToolCallStatus, } from '@google/gemini-cli-core';
import { useInactivityTimer } from '../../hooks/useInactivityTimer.js';
import { formatCommand } from '../../utils/keybindingUtils.js';
import { Command } from '../../../config/keyBindings.js';
export const STATUS_INDICATOR_WIDTH = 3;
/**
 * Returns true if the tool name corresponds to a shell tool.
 */
export function isShellTool(name) {
    return (name === SHELL_COMMAND_NAME ||
        name === SHELL_NAME ||
        name === SHELL_TOOL_NAME);
}
/**
 * Returns true if the shell tool call is currently focusable.
 */
export function isThisShellFocusable(name, status, config) {
    return !!(isShellTool(name) &&
        status === CoreToolCallStatus.Executing &&
        config?.getEnableInteractiveShell());
}
/**
 * Returns true if this specific shell tool call is currently focused.
 */
export function isThisShellFocused(name, status, ptyId, activeShellPtyId, embeddedShellFocused) {
    return !!(isShellTool(name) &&
        status === CoreToolCallStatus.Executing &&
        ptyId === activeShellPtyId &&
        embeddedShellFocused);
}
/**
 * Hook to manage focus hint state.
 */
export function useFocusHint(isThisShellFocusable, isThisShellFocused, resultDisplay) {
    const [userHasFocused, setUserHasFocused] = useState(false);
    // Derive a stable reset key for the inactivity timer. For strings and arrays
    // (shell output), we use the length to capture updates without referential
    // identity issues or expensive deep comparisons.
    const resetKey = typeof resultDisplay === 'string'
        ? resultDisplay.length
        : Array.isArray(resultDisplay)
            ? resultDisplay.length
            : !!resultDisplay;
    const showFocusHint = useInactivityTimer(isThisShellFocusable, resetKey, SHELL_FOCUS_HINT_DELAY_MS);
    useEffect(() => {
        if (isThisShellFocused) {
            setUserHasFocused(true);
        }
    }, [isThisShellFocused]);
    const shouldShowFocusHint = isThisShellFocusable && (showFocusHint || userHasFocused);
    return { shouldShowFocusHint };
}
/**
 * Component to render the focus hint.
 */
export const FocusHint = ({ shouldShowFocusHint, isThisShellFocused }) => {
    if (!shouldShowFocusHint) {
        return null;
    }
    return (_jsx(Box, { marginLeft: 1, flexShrink: 0, children: _jsx(Text, { color: theme.text.accent, children: isThisShellFocused
                ? `(${formatCommand(Command.UNFOCUS_SHELL_INPUT)} to unfocus)`
                : `(${formatCommand(Command.FOCUS_SHELL_INPUT)} to focus)` }) }));
};
export const ToolStatusIndicator = ({ status: coreStatus, name, }) => {
    const status = mapCoreStatusToDisplayStatus(coreStatus);
    const isShell = isShellTool(name);
    const statusColor = isShell ? theme.ui.symbol : theme.status.warning;
    return (_jsxs(Box, { minWidth: STATUS_INDICATOR_WIDTH, children: [status === ToolCallStatus.Pending && (_jsx(Text, { color: theme.status.success, children: TOOL_STATUS.PENDING })), status === ToolCallStatus.Executing && (_jsx(GeminiRespondingSpinner, { spinnerType: "toggle", nonRespondingDisplay: TOOL_STATUS.EXECUTING })), status === ToolCallStatus.Success && (_jsx(Text, { color: theme.status.success, "aria-label": 'Success:', children: TOOL_STATUS.SUCCESS })), status === ToolCallStatus.Confirming && (_jsx(Text, { color: statusColor, "aria-label": 'Confirming:', children: TOOL_STATUS.CONFIRMING })), status === ToolCallStatus.Canceled && (_jsx(Text, { color: statusColor, "aria-label": 'Canceled:', bold: true, children: TOOL_STATUS.CANCELED })), status === ToolCallStatus.Error && (_jsx(Text, { color: theme.status.error, "aria-label": 'Error:', bold: true, children: TOOL_STATUS.ERROR }))] }));
};
export const ToolInfo = ({ name, description, status: coreStatus, emphasis, originalRequestName, }) => {
    const status = mapCoreStatusToDisplayStatus(coreStatus);
    const nameColor = React.useMemo(() => {
        switch (emphasis) {
            case 'high':
                return theme.text.primary;
            case 'medium':
                return theme.text.primary;
            case 'low':
                return theme.text.secondary;
            default: {
                const exhaustiveCheck = emphasis;
                return exhaustiveCheck;
            }
        }
    }, [emphasis]);
    // Hide description for completed Ask User tools (the result display speaks for itself)
    const isCompletedAskUser = isCompletedAskUserTool(name, status);
    return (_jsx(Box, { overflow: "hidden", height: 1, flexGrow: 1, flexShrink: 1, children: _jsxs(Text, { strikethrough: status === ToolCallStatus.Canceled, wrap: "truncate", children: [_jsx(Text, { color: nameColor, bold: true, children: name }), originalRequestName && originalRequestName !== name && (_jsxs(Text, { color: theme.text.secondary, italic: true, children: [' ', "(redirection from ", originalRequestName, ")"] })), !isCompletedAskUser && (_jsxs(_Fragment, { children: [' ', _jsx(Text, { color: theme.text.secondary, children: description })] }))] }) }));
};
export const McpProgressIndicator = ({ progress, total, message, barWidth, }) => {
    const percentage = total && total > 0
        ? Math.min(100, Math.round((progress / total) * 100))
        : null;
    let rawFilled;
    if (total && total > 0) {
        rawFilled = Math.round((progress / total) * barWidth);
    }
    else {
        rawFilled = Math.floor(progress) % (barWidth + 1);
    }
    const filled = Math.max(0, Math.min(Number.isFinite(rawFilled) ? rawFilled : 0, barWidth));
    const empty = Math.max(0, barWidth - filled);
    const progressBar = '\u2588'.repeat(filled) + '\u2591'.repeat(empty);
    return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { children: _jsxs(Text, { color: theme.text.accent, children: [progressBar, " ", percentage !== null ? `${percentage}%` : `${progress}`] }) }), message && (_jsx(Text, { color: theme.text.secondary, wrap: "truncate", children: message }))] }));
};
export const TrailingIndicator = () => (_jsxs(Text, { color: theme.text.primary, wrap: "truncate", children: [' ', "\u2190"] }));
//# sourceMappingURL=ToolShared.js.map