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

import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { renderHook } from '../../test-utils/render.js';
import { useTurnActivityMonitor } from './useTurnActivityMonitor.js';
import { StreamingState } from '../types.js';
import { hasRedirection, CoreToolCallStatus } from '@google/gemini-cli-core';
import { type TrackedToolCall } from './useToolScheduler.js';

vi.mock('@google/gemini-cli-core', async (importOriginal) => {
  const actual = await importOriginal<Record<string, unknown>>();
  return {
    ...actual,
    hasRedirection: vi.fn(),
  };
});

describe('useTurnActivityMonitor', () => {
  beforeEach(() => {
    vi.useFakeTimers();
    vi.setSystemTime(1000);
    vi.mocked(hasRedirection).mockImplementation(
      (query: string) => query.includes('>') || query.includes('>>'),
    );
  });

  afterEach(() => {
    vi.clearAllMocks();
    vi.useRealTimers();
  });

  it('should set operationStartTime when entering Responding state', async () => {
    const { result, rerender } = await renderHook(
      ({ state }) => useTurnActivityMonitor(state, null, []),
      {
        initialProps: { state: StreamingState.Idle },
      },
    );

    // Reset time to 1000 to counter the 50ms advanced by renderHook's wait
    vi.setSystemTime(1000);

    expect(result.current.operationStartTime).toBe(0);

    rerender({ state: StreamingState.Responding });
    expect(result.current.operationStartTime).toBe(1000);
  });

  it('should reset operationStartTime when PTY ID changes while responding', async () => {
    const { result, rerender } = await renderHook(
      ({ state, ptyId }) => useTurnActivityMonitor(state, ptyId, []),
      {
        initialProps: {
          state: StreamingState.Responding,
          ptyId: 'pty-1' as string | null,
        },
      },
    );

    expect(result.current.operationStartTime).toBe(1000);

    vi.setSystemTime(2000);
    rerender({ state: StreamingState.Responding, ptyId: 'pty-2' });
    expect(result.current.operationStartTime).toBe(2000);
  });

  it('should detect redirection from tool calls', async () => {
    // Force mock implementation to ensure it's active
    vi.mocked(hasRedirection).mockImplementation((q: string) =>
      q.includes('>'),
    );

    const { result, rerender } = await renderHook(
      ({ state, pendingToolCalls }) =>
        useTurnActivityMonitor(state, null, pendingToolCalls),
      {
        initialProps: {
          state: StreamingState.Responding,
          pendingToolCalls: [] as TrackedToolCall[],
        },
      },
    );

    expect(result.current.isRedirectionActive).toBe(false);

    // Test non-redirected tool call
    rerender({
      state: StreamingState.Responding,
      pendingToolCalls: [
        {
          request: {
            name: 'run_shell_command',
            args: { command: 'ls -la' },
          },
          status: CoreToolCallStatus.Executing,
        } as unknown as TrackedToolCall,
      ],
    });
    expect(result.current.isRedirectionActive).toBe(false);

    // Test tool call redirection
    rerender({
      state: StreamingState.Responding,
      pendingToolCalls: [
        {
          request: {
            name: 'run_shell_command',
            args: { command: 'ls > tool_out.txt' },
          },
          status: CoreToolCallStatus.Executing,
        } as unknown as TrackedToolCall,
      ],
    });
    expect(result.current.isRedirectionActive).toBe(true);
  });

  it('should reset everything when idle', async () => {
    const { result, rerender } = await renderHook(
      ({ state }) => useTurnActivityMonitor(state, 'pty-1', []),
      {
        initialProps: { state: StreamingState.Responding },
      },
    );

    expect(result.current.operationStartTime).toBe(1000);

    rerender({ state: StreamingState.Idle });
    expect(result.current.operationStartTime).toBe(0);
  });
});
