import { fireEvent, render, screen } from '@testing-library/react';
import { describe, expect, it, vi } from 'vitest';
import { ExecutionGraphCard, formatExecutionDuration } from '@/pages/Chat/ExecutionGraphCard';
import { getToolVisibilityId } from '@/pages/Chat/chat-transcript';
import type { TaskStep } from '@/pages/Chat/task-visualization';

vi.mock('react-i18next', async (importOriginal) => {
  const actual = await importOriginal<typeof import('react-i18next')>();
  return {
    ...actual,
    useTranslation: () => ({
      t: (key: string) => key,
    }),
  };
});

describe('ExecutionGraphCard', () => {
  it('shows only duration units that have elapsed', () => {
    expect(formatExecutionDuration(2_500)).toBe('2s');
    expect(formatExecutionDuration(62_500)).toBe('1m 2s');
    expect(formatExecutionDuration(3_661_500)).toBe('1h 1m 1s');
    expect(formatExecutionDuration(undefined)).toBe('—');
  });

  it('uses muted styling for the collapsed duration summary', () => {
    render(
      <ExecutionGraphCard
        agentLabel="Makelore"
        steps={[]}
        active={false}
        durationMs={2_500}
      />,
    );

    const summary = screen
      .getByTestId('chat-execution-graph-expand')
      .querySelector('span.truncate');
    expect(summary).not.toBeNull();
    expect(summary).toHaveClass('text-muted-foreground/70');
    expect(summary).not.toHaveClass('text-foreground');
  });

  it('places the expand control after the duration summary', () => {
    render(
      <ExecutionGraphCard
        agentLabel="Makelore"
        steps={[]}
        active={false}
        durationMs={2_500}
      />,
    );

    const button = screen.getByTestId('chat-execution-graph-expand');
    const summary = button.querySelector('span.truncate');
    expect(summary).not.toBeNull();
    expect(summary?.nextElementSibling).toHaveClass('h-5', 'w-5');
  });

  it('shows the current process summary while the graph is active', () => {
    render(
      <ExecutionGraphCard
        agentLabel="Makelore"
        steps={[{
          id: 'tool-fetch',
          label: 'web_fetch',
          status: 'running',
          kind: 'tool',
          depth: 1,
        }]}
        active
        expanded
      />,
    );

    expect(screen.getByTestId('chat-execution-graph-collapse')).toHaveTextContent('web_fetch');
  });

  it('drives the real graph step detail from the shared visibility set', () => {
    const visibilityId = getToolVisibilityId('msg_assistant', 'tool-read', 0);
    const onStepExpandedChange = vi.fn();
    const step: TaskStep = {
      id: 'tool-read',
      visibilityId,
      label: 'read',
      status: 'completed',
      kind: 'tool',
      detail: '{"file":"README.md"}',
      depth: 1,
    };
    const { rerender } = render(
      <ExecutionGraphCard
        agentLabel="Makelore"
        steps={[step]}
        active={false}
        expanded
        expandedStepIds={new Set()}
        onStepExpandedChange={onStepExpandedChange}
      />,
    );

    expect(screen.getByText(/README\.md/).closest('[data-state]')).toHaveAttribute('data-state', 'closed');
    fireEvent.click(screen.getByRole('button', { name: /read/i }));
    expect(onStepExpandedChange).toHaveBeenCalledWith(visibilityId, true);

    rerender(
      <ExecutionGraphCard
        agentLabel="Makelore"
        steps={[step]}
        active={false}
        expanded
        expandedStepIds={new Set([visibilityId])}
        onStepExpandedChange={onStepExpandedChange}
      />,
    );
    expect(screen.getByText(/"file": "README\.md"/)).toBeInTheDocument();
  });

  it('notifies the parent when an uncontrolled active graph auto-collapses', () => {
    const onExpandedChange = vi.fn();
    const step: TaskStep = {
      id: 'tool-read',
      label: 'read',
      status: 'running',
      kind: 'tool',
      detail: '{"file":"README.md"}',
      depth: 1,
    };
    const { rerender } = render(
      <ExecutionGraphCard
        agentLabel="娉ュ湡"
        steps={[step]}
        active
        onExpandedChange={onExpandedChange}
      />,
    );
    expect(screen.getByTestId('chat-execution-graph')).toHaveAttribute(
      'data-collapsed',
      'true',
    );

    fireEvent.click(screen.getByTestId('chat-execution-graph-expand'));
    expect(screen.getByTestId('chat-execution-graph')).toHaveAttribute(
      'data-collapsed',
      'false',
    );

    rerender(
      <ExecutionGraphCard
        agentLabel="娉ュ湡"
        steps={[{ ...step, status: 'completed' }]}
        active={false}
        onExpandedChange={onExpandedChange}
      />,
    );

    expect(screen.getByTestId('chat-execution-graph')).toHaveAttribute(
      'data-collapsed',
      'true',
    );
    expect(onExpandedChange).toHaveBeenCalledWith(false);
  });

  it('notifies the parent when a completed uncontrolled graph mounts collapsed', () => {
    const onExpandedChange = vi.fn();
    render(
      <ExecutionGraphCard
        agentLabel="娉ュ湡"
        steps={[{
          id: 'tool-read',
          label: 'read',
          status: 'completed',
          kind: 'tool',
          detail: '{"file":"README.md"}',
          depth: 1,
        }]}
        active={false}
        onExpandedChange={onExpandedChange}
      />,
    );

    expect(onExpandedChange).toHaveBeenCalledWith(false);
  });
});
