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

import { renderWithProviders } from '../../../test-utils/render.js';
import { describe, it, expect, vi, afterEach } from 'vitest';
import { ToolGroupMessage } from './ToolGroupMessage.js';
import {
  UPDATE_TOPIC_TOOL_NAME,
  TOPIC_PARAM_TITLE,
  TOPIC_PARAM_SUMMARY,
  TOPIC_PARAM_STRATEGIC_INTENT,
  makeFakeConfig,
  CoreToolCallStatus,
  ApprovalMode,
  ASK_USER_DISPLAY_NAME,
  WRITE_FILE_DISPLAY_NAME,
  EDIT_DISPLAY_NAME,
  READ_FILE_DISPLAY_NAME,
  GLOB_DISPLAY_NAME,
} from '@google/gemini-cli-core';
import type {
  HistoryItem,
  HistoryItemWithoutId,
  IndividualToolCallDisplay,
} from '../../types.js';
import { Scrollable } from '../shared/Scrollable.js';
import os from 'node:os';
import { createMockSettings } from '../../../test-utils/settings.js';

describe('<ToolGroupMessage />', () => {
  afterEach(() => {
    vi.restoreAllMocks();
  });

  const createToolCall = (
    overrides: Partial<IndividualToolCallDisplay> = {},
  ): IndividualToolCallDisplay => ({
    callId: 'tool-123',
    name: 'test-tool',
    args: {},
    description: 'A tool for testing',
    resultDisplay: 'Test result',
    status: CoreToolCallStatus.Success,
    confirmationDetails: undefined,
    renderOutputAsMarkdown: false,
    ...overrides,
  });

  const baseProps = {
    terminalWidth: 80,
  };

  const createItem = (
    tools: IndividualToolCallDisplay[],
  ): HistoryItem | HistoryItemWithoutId => ({
    id: 1,
    type: 'tool_group',
    tools,
  });

  const baseMockConfig = makeFakeConfig({
    model: 'gemini-pro',
    targetDir: os.tmpdir(),
    debugMode: false,
    folderTrust: false,
    ideMode: false,
    enableInteractiveShell: true,
  });
  const fullVerbositySettings = createMockSettings({
    ui: { errorVerbosity: 'full' },
  });
  const lowVerbositySettings = createMockSettings({
    ui: { errorVerbosity: 'low' },
  });

  describe('Golden Snapshots', () => {
    it('renders single successful tool call', async () => {
      const toolCalls = [createToolCall()];
      const item = createItem(toolCalls);
      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
        {
          config: baseMockConfig,
          settings: fullVerbositySettings,
          uiState: {
            pendingHistoryItems: [
              {
                type: 'tool_group',
                tools: toolCalls,
              },
            ],
          },
        },
      );
      expect(lastFrame({ allowEmpty: true })).toMatchSnapshot();
      unmount();
    });

    it('hides confirming tools (standard behavior)', async () => {
      const toolCalls = [
        createToolCall({
          callId: 'confirm-tool',
          status: CoreToolCallStatus.AwaitingApproval,
          confirmationDetails: {
            type: 'info',
            title: 'Confirm tool',
            prompt: 'Do you want to proceed?',
          },
        }),
      ];
      const item = createItem(toolCalls);

      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
        { config: baseMockConfig, settings: fullVerbositySettings },
      );

      // Should now hide confirming tools (to avoid duplication with Global Queue)
      expect(lastFrame({ allowEmpty: true })).toBe('');
      unmount();
    });

    it('renders canceled tool calls', async () => {
      const toolCalls = [
        createToolCall({
          callId: 'canceled-tool',
          name: 'canceled-tool',
          status: CoreToolCallStatus.Cancelled,
        }),
      ];
      const item = createItem(toolCalls);

      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
        { config: baseMockConfig, settings: fullVerbositySettings },
      );

      const output = lastFrame();
      expect(output).toMatchSnapshot('canceled_tool');
      unmount();
    });

    it('renders multiple tool calls with different statuses (only visible ones)', async () => {
      const toolCalls = [
        createToolCall({
          callId: 'tool-1',
          name: 'successful-tool',
          description: 'This tool succeeded',
          status: CoreToolCallStatus.Success,
        }),
        createToolCall({
          callId: 'tool-2',
          name: 'pending-tool',
          description: 'This tool is pending',
          status: CoreToolCallStatus.Scheduled,
        }),
        createToolCall({
          callId: 'tool-3',
          name: 'error-tool',
          description: 'This tool failed',
          status: CoreToolCallStatus.Error,
        }),
      ];
      const item = createItem(toolCalls);

      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
        {
          config: baseMockConfig,
          settings: fullVerbositySettings,
          uiState: {
            pendingHistoryItems: [
              {
                type: 'tool_group',
                tools: toolCalls,
              },
            ],
          },
        },
      );
      // pending-tool should now be visible
      const output = lastFrame();
      expect(output).toContain('successful-tool');
      expect(output).toContain('pending-tool');
      expect(output).toContain('error-tool');
      expect(output).toMatchSnapshot();
      unmount();
    });

    it('hides errored tool calls in low error verbosity mode', async () => {
      const toolCalls = [
        createToolCall({
          callId: 'tool-1',
          name: 'successful-tool',
          status: CoreToolCallStatus.Success,
        }),
        createToolCall({
          callId: 'tool-2',
          name: 'error-tool',
          status: CoreToolCallStatus.Error,
          resultDisplay: 'Tool failed',
        }),
      ];
      const item = createItem(toolCalls);

      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
        {
          config: baseMockConfig,
          uiState: {
            pendingHistoryItems: [
              {
                type: 'tool_group',
                tools: toolCalls,
              },
            ],
          },
        },
      );
      const output = lastFrame();
      expect(output).toContain('successful-tool');
      expect(output).not.toContain('error-tool');
      unmount();
    });

    it('keeps client-initiated errored tool calls visible in low error verbosity mode', async () => {
      const toolCalls = [
        createToolCall({
          callId: 'tool-1',
          name: 'client-error-tool',
          status: CoreToolCallStatus.Error,
          isClientInitiated: true,
          resultDisplay: 'Client tool failed',
        }),
      ];
      const item = createItem(toolCalls);

      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
        {
          config: baseMockConfig,
          uiState: {
            pendingHistoryItems: [
              {
                type: 'tool_group',
                tools: toolCalls,
              },
            ],
          },
        },
      );

      const output = lastFrame();
      expect(output).toContain('client-error-tool');
      unmount();
    });

    it('renders update_topic tool call using TopicMessage', async () => {
      const toolCalls = [
        createToolCall({
          callId: 'topic-tool',
          name: UPDATE_TOPIC_TOOL_NAME,
          args: {
            [TOPIC_PARAM_TITLE]: 'Testing Topic',
            [TOPIC_PARAM_STRATEGIC_INTENT]: 'This is the description',
          },
        }),
      ];
      const item = createItem(toolCalls);

      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
        {
          config: baseMockConfig,
          settings: fullVerbositySettings,
        },
      );

      const output = lastFrame();
      expect(output).toContain('Testing Topic: ');
      expect(output).toContain('This is the description');
      expect(output).toMatchSnapshot('update_topic_tool');
      unmount();
    });

    it('renders update_topic tool call with summary instead of strategic_intent', async () => {
      const toolCalls = [
        createToolCall({
          callId: 'topic-tool-summary',
          name: UPDATE_TOPIC_TOOL_NAME,
          args: {
            [TOPIC_PARAM_TITLE]: 'Testing Topic',
            [TOPIC_PARAM_SUMMARY]: 'This is the summary',
          },
        }),
      ];
      const item = createItem(toolCalls);

      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
        {
          config: baseMockConfig,
          settings: fullVerbositySettings,
        },
      );

      const output = lastFrame();
      expect(output).toContain('Testing Topic: ');
      expect(output).toContain('This is the summary');
      unmount();
    });

    it('renders mixed tool calls including update_topic', async () => {
      const toolCalls = [
        createToolCall({
          callId: 'topic-tool-mixed',
          name: UPDATE_TOPIC_TOOL_NAME,
          args: {
            [TOPIC_PARAM_TITLE]: 'Testing Topic',
            [TOPIC_PARAM_STRATEGIC_INTENT]: 'This is the description',
          },
        }),
        createToolCall({
          callId: 'tool-1',
          name: 'read_file',
          description: 'Read a file',
          status: CoreToolCallStatus.Success,
        }),
        createToolCall({
          callId: 'tool-2',
          name: 'run_shell_command',
          description: 'Run command',
          status: CoreToolCallStatus.Executing,
        }),
        createToolCall({
          callId: 'tool-3',
          name: 'write_file',
          description: 'Write to file',
          status: CoreToolCallStatus.Scheduled,
        }),
      ];
      const item = createItem(toolCalls);

      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
        {
          config: baseMockConfig,
          settings: fullVerbositySettings,
          uiState: {
            pendingHistoryItems: [
              {
                type: 'tool_group',
                tools: toolCalls,
              },
            ],
          },
        },
      );
      // write_file (Pending) should now be visible
      const output = lastFrame();
      expect(output).toContain('read_file');
      expect(output).toContain('run_shell_command');
      expect(output).toContain('write_file');
      expect(output).toMatchSnapshot();
      unmount();
    });

    it('renders update_topic in the middle of other tools', async () => {
      const toolCalls = [
        createToolCall({
          callId: 'tool-1',
          name: 'read_file',
          status: CoreToolCallStatus.Success,
        }),
        createToolCall({
          callId: 'topic-tool-middle',
          name: UPDATE_TOPIC_TOOL_NAME,
          args: {
            [TOPIC_PARAM_TITLE]: 'Middle Topic',
          },
        }),
        createToolCall({
          callId: 'tool-2',
          name: 'write_file',
          status: CoreToolCallStatus.Success,
        }),
      ];
      const item = createItem(toolCalls);

      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
        {
          config: baseMockConfig,
          settings: fullVerbositySettings,
        },
      );
      expect(lastFrame()).toMatchSnapshot('update_topic_middle');
      unmount();
    });

    it('renders with limited terminal height', async () => {
      const toolCalls = [
        createToolCall({
          callId: 'tool-1',
          name: 'tool-with-result',
          description: 'Tool with output',
          resultDisplay:
            'This is a long result that might need height constraints',
        }),
        createToolCall({
          callId: 'tool-2',
          name: 'another-tool',
          description: 'Another tool',
          resultDisplay: 'More output here',
        }),
      ];
      const item = createItem(toolCalls);
      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage
          {...baseProps}
          item={item}
          toolCalls={toolCalls}
          availableTerminalHeight={10}
        />,
        {
          config: baseMockConfig,
          settings: fullVerbositySettings,
          uiState: {
            pendingHistoryItems: [
              {
                type: 'tool_group',
                tools: toolCalls,
              },
            ],
          },
        },
      );
      expect(lastFrame({ allowEmpty: true })).toMatchSnapshot();
      unmount();
    });

    it('renders with narrow terminal width', async () => {
      const toolCalls = [
        createToolCall({
          name: 'very-long-tool-name-that-might-wrap',
          description:
            'This is a very long description that might cause wrapping issues',
        }),
      ];
      const item = createItem(toolCalls);
      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage
          {...baseProps}
          item={item}
          toolCalls={toolCalls}
          terminalWidth={40}
        />,
        {
          config: baseMockConfig,
          settings: fullVerbositySettings,
          uiState: {
            pendingHistoryItems: [
              {
                type: 'tool_group',
                tools: toolCalls,
              },
            ],
          },
        },
      );
      expect(lastFrame({ allowEmpty: true })).toMatchSnapshot();
      unmount();
    });

    it('renders empty tool calls array', async () => {
      const toolCalls: IndividualToolCallDisplay[] = [];
      const item = createItem(toolCalls);
      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
        {
          config: baseMockConfig,
          settings: fullVerbositySettings,
          uiState: {
            pendingHistoryItems: [
              {
                type: 'tool_group',
                tools: [],
              },
            ],
          },
        },
      );
      expect(lastFrame({ allowEmpty: true })).toMatchSnapshot();
      unmount();
    });

    it('renders header when scrolled', async () => {
      const toolCalls = [
        createToolCall({
          callId: '1',
          name: 'tool-1',
          description:
            'Description 1. This is a long description that will need to be truncated if the terminal width is small.',
          resultDisplay: 'line1\nline2\nline3\nline4\nline5',
        }),
        createToolCall({
          callId: '2',
          name: 'tool-2',
          description: 'Description 2',
          resultDisplay: 'line1\nline2',
        }),
      ];
      const item = createItem(toolCalls);
      const { lastFrame, unmount } = await renderWithProviders(
        <Scrollable height={12} hasFocus={true} scrollToBottom={true}>
          <ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />
        </Scrollable>,
        {
          config: baseMockConfig,
          settings: fullVerbositySettings,
          uiState: {
            pendingHistoryItems: [
              {
                type: 'tool_group',
                tools: toolCalls,
              },
            ],
          },
        },
      );
      expect(lastFrame({ allowEmpty: true })).toMatchSnapshot();
      unmount();
    });

    it('renders tool call with outputFile', async () => {
      const toolCalls = [
        createToolCall({
          callId: 'tool-output-file',
          name: 'tool-with-file',
          description: 'Tool that saved output to file',
          status: CoreToolCallStatus.Success,
          outputFile: '/path/to/output.txt',
        }),
      ];
      const item = createItem(toolCalls);
      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
        {
          config: baseMockConfig,
          settings: fullVerbositySettings,
          uiState: {
            pendingHistoryItems: [
              {
                type: 'tool_group',
                tools: toolCalls,
              },
            ],
          },
        },
      );
      expect(lastFrame({ allowEmpty: true })).toMatchSnapshot();
      unmount();
    });

    it('renders two tool groups where only the last line of the previous group is visible', async () => {
      const toolCalls1 = [
        createToolCall({
          callId: '1',
          name: 'tool-1',
          description: 'Description 1',
          resultDisplay: 'line1\nline2\nline3\nline4\nline5',
        }),
      ];
      const item1 = createItem(toolCalls1);
      const toolCalls2 = [
        createToolCall({
          callId: '2',
          name: 'tool-2',
          description: 'Description 2',
          resultDisplay: 'line1',
        }),
      ];
      const item2 = createItem(toolCalls2);

      const { lastFrame, unmount } = await renderWithProviders(
        <Scrollable height={6} hasFocus={true} scrollToBottom={true}>
          <ToolGroupMessage
            {...baseProps}
            item={item1}
            toolCalls={toolCalls1}
          />
          <ToolGroupMessage
            {...baseProps}
            item={item2}
            toolCalls={toolCalls2}
          />
        </Scrollable>,
        {
          config: baseMockConfig,
          settings: fullVerbositySettings,
          uiState: {
            pendingHistoryItems: [
              {
                type: 'tool_group',
                tools: toolCalls1,
              },
              {
                type: 'tool_group',
                tools: toolCalls2,
              },
            ],
          },
        },
      );
      expect(lastFrame({ allowEmpty: true })).toMatchSnapshot();
      unmount();
    });
  });

  describe('Border Color Logic', () => {
    it('uses yellow border for shell commands even when successful', async () => {
      const toolCalls = [
        createToolCall({
          name: 'run_shell_command',
          status: CoreToolCallStatus.Success,
        }),
      ];
      const item = createItem(toolCalls);
      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
        {
          config: baseMockConfig,
          settings: fullVerbositySettings,
          uiState: {
            pendingHistoryItems: [
              {
                type: 'tool_group',
                tools: toolCalls,
              },
            ],
          },
        },
      );
      expect(lastFrame({ allowEmpty: true })).toMatchSnapshot();
      unmount();
    });

    it('uses gray border when all tools are successful and no shell commands', async () => {
      const toolCalls = [
        createToolCall({ status: CoreToolCallStatus.Success }),
        createToolCall({
          callId: 'tool-2',
          name: 'another-tool',
          status: CoreToolCallStatus.Success,
        }),
      ];
      const item = createItem(toolCalls);
      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
        {
          config: baseMockConfig,
          settings: fullVerbositySettings,
          uiState: {
            pendingHistoryItems: [
              {
                type: 'tool_group',
                tools: toolCalls,
              },
            ],
          },
        },
      );
      expect(lastFrame({ allowEmpty: true })).toMatchSnapshot();
      unmount();
    });
  });

  describe('Height Calculation', () => {
    it('calculates available height correctly with multiple tools with results', async () => {
      const toolCalls = [
        createToolCall({
          callId: 'tool-1',
          resultDisplay: 'Result 1',
        }),
        createToolCall({
          callId: 'tool-2',
          resultDisplay: 'Result 2',
        }),
        createToolCall({
          callId: 'tool-3',
          resultDisplay: '', // No result
        }),
      ];
      const item = createItem(toolCalls);
      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage
          {...baseProps}
          item={item}
          toolCalls={toolCalls}
          availableTerminalHeight={20}
        />,
        {
          config: baseMockConfig,
          settings: fullVerbositySettings,
          uiState: {
            pendingHistoryItems: [
              {
                type: 'tool_group',
                tools: toolCalls,
              },
            ],
          },
        },
      );
      expect(lastFrame({ allowEmpty: true })).toMatchSnapshot();
      unmount();
    });
  });

  describe('Ask User Filtering', () => {
    it.each([
      {
        status: CoreToolCallStatus.Scheduled,
        resultDisplay: 'test result',
        shouldHide: true,
      },
      {
        status: CoreToolCallStatus.Executing,
        resultDisplay: 'test result',
        shouldHide: true,
      },
      {
        status: CoreToolCallStatus.AwaitingApproval,
        resultDisplay: 'test result',
        shouldHide: true,
      },
      {
        status: CoreToolCallStatus.Success,
        resultDisplay: 'test result',
        shouldHide: false,
      },
      { status: CoreToolCallStatus.Error, resultDisplay: '', shouldHide: true },
      {
        status: CoreToolCallStatus.Error,
        resultDisplay: 'error message',
        shouldHide: false,
      },
    ])(
      'filtering logic for status=$status and hasResult=$resultDisplay',
      async ({ status, resultDisplay, shouldHide }) => {
        const toolCalls = [
          createToolCall({
            callId: `ask-user-${status}`,
            name: ASK_USER_DISPLAY_NAME,
            status,
            resultDisplay,
          }),
        ];
        const item = createItem(toolCalls);

        const { lastFrame, unmount } = await renderWithProviders(
          <ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
          { config: baseMockConfig, settings: fullVerbositySettings },
        );
        if (shouldHide) {
          expect(lastFrame({ allowEmpty: true })).toBe('');
        } else {
          expect(lastFrame()).toMatchSnapshot();
        }
        unmount();
      },
    );

    it('shows other tools when ask_user is filtered out', async () => {
      const toolCalls = [
        createToolCall({
          callId: 'other-tool',
          name: 'other-tool',
          status: CoreToolCallStatus.Success,
        }),
        createToolCall({
          callId: 'ask-user-pending',
          name: ASK_USER_DISPLAY_NAME,
          status: CoreToolCallStatus.Scheduled,
        }),
      ];
      const item = createItem(toolCalls);

      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
        { config: baseMockConfig, settings: fullVerbositySettings },
      );

      expect(lastFrame({ allowEmpty: true })).toMatchSnapshot();
      unmount();
    });

    it('renders nothing when only tool is in-progress AskUser with borderBottom=false', async () => {
      // AskUser tools in progress are rendered by AskUserDialog, not ToolGroupMessage.
      // When AskUser is the only tool and borderBottom=false (no border to close),
      // the component should render nothing.
      const toolCalls = [
        createToolCall({
          callId: 'ask-user-tool',
          name: ASK_USER_DISPLAY_NAME,
          status: CoreToolCallStatus.Executing,
        }),
      ];
      const item = createItem(toolCalls);

      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage
          {...baseProps}
          item={item}
          toolCalls={toolCalls}
          borderBottom={false}
        />,
        { config: baseMockConfig, settings: fullVerbositySettings },
      );
      // AskUser tools in progress are rendered by AskUserDialog, so we expect nothing.
      expect(lastFrame({ allowEmpty: true })).toBe('');
      unmount();
    });

    it('does not render a bottom-border fragment when all tools are filtered out', async () => {
      const toolCalls = [
        createToolCall({
          callId: 'hidden-error-tool',
          name: 'error-tool',
          status: CoreToolCallStatus.Error,
          resultDisplay: 'Hidden in low verbosity',
          isClientInitiated: false,
        }),
      ];
      const item = createItem(toolCalls);

      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage
          {...baseProps}
          item={item}
          toolCalls={toolCalls}
          borderTop={false}
          borderBottom={true}
        />,
        {
          config: baseMockConfig,
          settings: lowVerbositySettings,
        },
      );

      expect(lastFrame({ allowEmpty: true })).toBe('');
      unmount();
    });

    it('still renders explicit closing slices for split static/pending groups', async () => {
      const toolCalls: IndividualToolCallDisplay[] = [];
      const item = createItem(toolCalls);

      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage
          {...baseProps}
          item={item}
          toolCalls={toolCalls}
          borderTop={false}
          borderBottom={true}
        />,
        {
          config: baseMockConfig,
          settings: fullVerbositySettings,
        },
      );

      expect(lastFrame({ allowEmpty: true })).not.toBe('');
      unmount();
    });

    it('does not render a border fragment when plan-mode tools are filtered out', async () => {
      const toolCalls = [
        createToolCall({
          callId: 'plan-write',
          name: WRITE_FILE_DISPLAY_NAME,
          approvalMode: ApprovalMode.PLAN,
          status: CoreToolCallStatus.Success,
          resultDisplay: 'Plan file written',
        }),
      ];
      const item = createItem(toolCalls);

      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage
          {...baseProps}
          item={item}
          toolCalls={toolCalls}
          borderTop={false}
          borderBottom={true}
        />,
        {
          config: baseMockConfig,
          settings: fullVerbositySettings,
        },
      );

      expect(lastFrame({ allowEmpty: true })).toBe('');
      unmount();
    });

    it('does not render a border fragment when only confirming tools are present', async () => {
      const toolCalls = [
        createToolCall({
          callId: 'confirm-only',
          status: CoreToolCallStatus.AwaitingApproval,
          confirmationDetails: {
            type: 'info',
            title: 'Confirm',
            prompt: 'Proceed?',
          },
        }),
      ];
      const item = createItem(toolCalls);

      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage
          {...baseProps}
          item={item}
          toolCalls={toolCalls}
          borderTop={false}
          borderBottom={true}
        />,
        {
          config: baseMockConfig,
          settings: fullVerbositySettings,
        },
      );

      expect(lastFrame({ allowEmpty: true })).toBe('');
      unmount();
    });

    it('does not leave a border stub when transitioning from visible to fully filtered tools', async () => {
      const visibleTools = [
        createToolCall({
          callId: 'visible-success',
          name: 'visible-tool',
          status: CoreToolCallStatus.Success,
          resultDisplay: 'visible output',
        }),
      ];
      const hiddenTools = [
        createToolCall({
          callId: 'hidden-error',
          name: 'hidden-error-tool',
          status: CoreToolCallStatus.Error,
          resultDisplay: 'hidden output',
          isClientInitiated: false,
        }),
      ];

      const initialItem = createItem(visibleTools);
      const hiddenItem = createItem(hiddenTools);

      const firstRender = await renderWithProviders(
        <ToolGroupMessage
          {...baseProps}
          item={initialItem}
          toolCalls={visibleTools}
          borderTop={false}
          borderBottom={true}
        />,
        {
          config: baseMockConfig,
          settings: lowVerbositySettings,
        },
      );
      await firstRender.waitUntilReady();
      expect(firstRender.lastFrame()).toContain('visible-tool');
      firstRender.unmount();

      const secondRender = await renderWithProviders(
        <ToolGroupMessage
          {...baseProps}
          item={hiddenItem}
          toolCalls={hiddenTools}
          borderTop={false}
          borderBottom={true}
        />,
        {
          config: baseMockConfig,
          settings: lowVerbositySettings,
        },
      );
      await secondRender.waitUntilReady();
      expect(secondRender.lastFrame({ allowEmpty: true })).toBe('');
      secondRender.unmount();
    });

    it('keeps visible tools rendered with many filtered tools (stress case)', async () => {
      const visibleTool = createToolCall({
        callId: 'visible-tool',
        name: 'visible-tool',
        status: CoreToolCallStatus.Success,
        resultDisplay: 'visible output',
      });
      const hiddenTools = Array.from({ length: 50 }, (_, index) =>
        createToolCall({
          callId: `hidden-${index}`,
          name: `hidden-error-${index}`,
          status: CoreToolCallStatus.Error,
          resultDisplay: `hidden output ${index}`,
          isClientInitiated: false,
        }),
      );
      const toolCalls = [visibleTool, ...hiddenTools];
      const item = createItem(toolCalls);

      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage
          {...baseProps}
          item={item}
          toolCalls={toolCalls}
          borderTop={false}
          borderBottom={true}
        />,
        {
          config: baseMockConfig,
          settings: lowVerbositySettings,
        },
      );

      const output = lastFrame();
      expect(output).toContain('visible-tool');
      expect(output).not.toContain('hidden-error-0');
      expect(output).not.toContain('hidden-error-49');
      unmount();
    });

    it('renders explicit closing slice even at very narrow terminal width', async () => {
      const toolCalls: IndividualToolCallDisplay[] = [];
      const item = createItem(toolCalls);

      const { lastFrame, unmount } = await renderWithProviders(
        <ToolGroupMessage
          item={item}
          toolCalls={toolCalls}
          terminalWidth={8}
          borderTop={false}
          borderBottom={true}
        />,
        {
          config: baseMockConfig,
          settings: fullVerbositySettings,
        },
      );

      expect(lastFrame({ allowEmpty: true })).not.toBe('');
      unmount();
    });
  });

  describe('Plan Mode Filtering', () => {
    it.each([
      {
        name: WRITE_FILE_DISPLAY_NAME,
        mode: ApprovalMode.PLAN,
        visible: false,
      },
      { name: EDIT_DISPLAY_NAME, mode: ApprovalMode.PLAN, visible: false },
      {
        name: WRITE_FILE_DISPLAY_NAME,
        mode: ApprovalMode.DEFAULT,
        visible: true,
      },
      { name: READ_FILE_DISPLAY_NAME, mode: ApprovalMode.PLAN, visible: true },
      { name: GLOB_DISPLAY_NAME, mode: ApprovalMode.PLAN, visible: true },
    ])(
      'filtering logic for $name in $mode mode',
      async ({ name, mode, visible }) => {
        const toolCalls = [
          createToolCall({
            callId: 'test-call',
            name,
            approvalMode: mode,
          }),
        ];
        const item = createItem(toolCalls);

        const { lastFrame, unmount } = await renderWithProviders(
          <ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
          { config: baseMockConfig, settings: fullVerbositySettings },
        );

        if (visible) {
          expect(lastFrame()).toContain(name);
        } else {
          expect(lastFrame({ allowEmpty: true })).toBe('');
        }
        unmount();
      },
    );
  });
});
