/**
 * @license
 * Copyright 2026 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

import {
  ACTIVE_SHELL_MAX_LINES,
  COMPLETED_SHELL_MAX_LINES,
} from '../constants.js';
import { CoreToolCallStatus } from '@google/gemini-cli-core';

/**
 * Constants used for calculating available height for tool results.
 * These MUST be kept in sync between ToolGroupMessage (for overflow detection)
 * and ToolResultDisplay (for actual truncation).
 */
export const TOOL_RESULT_STATIC_HEIGHT = 1;
export const TOOL_RESULT_ASB_RESERVED_LINE_COUNT = 6;
export const TOOL_RESULT_STANDARD_RESERVED_LINE_COUNT = 3;
export const TOOL_RESULT_MIN_LINES_SHOWN = 2;

/**
 * The vertical space (in lines) consumed by the shell UI elements
 * (1 line for the shell title/header and 2 lines for the top and bottom borders).
 */
export const SHELL_CONTENT_OVERHEAD =
  TOOL_RESULT_STATIC_HEIGHT + TOOL_RESULT_STANDARD_RESERVED_LINE_COUNT;

/**
 * Calculates the final height available for the content of a tool result display.
 *
 * This accounts for:
 * 1. The static height of the tool message (name, status line).
 * 2. Reserved space for hints and padding (different in ASB vs Standard mode).
 * 3. Enforcing a minimum number of lines shown.
 */
export function calculateToolContentMaxLines(options: {
  availableTerminalHeight: number | undefined;
  isAlternateBuffer: boolean;
  maxLinesLimit?: number;
}): number | undefined {
  const { availableTerminalHeight, isAlternateBuffer, maxLinesLimit } = options;

  const reservedLines = isAlternateBuffer
    ? TOOL_RESULT_ASB_RESERVED_LINE_COUNT
    : TOOL_RESULT_STANDARD_RESERVED_LINE_COUNT;

  let contentHeight =
    availableTerminalHeight !== undefined
      ? Math.max(
          availableTerminalHeight - TOOL_RESULT_STATIC_HEIGHT - reservedLines,
          TOOL_RESULT_MIN_LINES_SHOWN + 1,
        )
      : undefined;

  if (maxLinesLimit !== undefined) {
    contentHeight =
      contentHeight !== undefined
        ? Math.min(contentHeight, maxLinesLimit)
        : maxLinesLimit;
  }

  return contentHeight;
}

/**
 * Calculates the maximum number of lines to display for shell output.
 *
 * This logic distinguishes between:
 * 1. Process Status: Active (Executing) vs Completed.
 * 2. UI Focus: Whether the user is currently interacting with the shell.
 * 3. Expansion State: Whether the user has explicitly requested to "Show More Lines" (CTRL+O).
 */
export function calculateShellMaxLines(options: {
  status: CoreToolCallStatus;
  isAlternateBuffer: boolean;
  isThisShellFocused: boolean;
  availableTerminalHeight: number | undefined;
  constrainHeight: boolean;
  isExpandable: boolean | undefined;
}): number | undefined {
  const {
    status,
    isAlternateBuffer,
    isThisShellFocused,
    availableTerminalHeight,
    constrainHeight,
    isExpandable,
  } = options;

  // 1. If the user explicitly requested expansion (unconstrained), remove all caps.
  if (!constrainHeight && isExpandable) {
    return undefined;
  }

  // 2. Handle cases where height is unknown (Standard mode history).
  if (availableTerminalHeight === undefined) {
    return isAlternateBuffer
      ? ACTIVE_SHELL_MAX_LINES - SHELL_CONTENT_OVERHEAD
      : undefined;
  }

  const maxLinesBasedOnHeight = Math.max(
    1,
    availableTerminalHeight - TOOL_RESULT_STANDARD_RESERVED_LINE_COUNT,
  );

  // 3. Handle ASB mode focus expansion.
  // We allow a focused shell in ASB mode to take up the full available height,
  // BUT only if we aren't trying to maintain a constrained view (e.g., history items).
  if (isAlternateBuffer && isThisShellFocused && !constrainHeight) {
    return maxLinesBasedOnHeight;
  }

  // 4. Fall back to process-based constants.
  const isExecuting = status === CoreToolCallStatus.Executing;
  const shellMaxLinesLimit = isExecuting
    ? ACTIVE_SHELL_MAX_LINES - SHELL_CONTENT_OVERHEAD
    : COMPLETED_SHELL_MAX_LINES - SHELL_CONTENT_OVERHEAD;

  return Math.min(maxLinesBasedOnHeight, shellMaxLinesLimit);
}
