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

import { describe, it, expect, vi, afterEach, beforeEach } from 'vitest';
import { renderWithProviders } from '../test-utils/render.js';
import { act } from 'react';
import { IdeIntegrationNudge } from './IdeIntegrationNudge.js';
import { debugLogger } from '@google/gemini-cli-core';

// Mock debugLogger
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
  const actual =
    await importOriginal<typeof import('@google/gemini-cli-core')>();
  return {
    ...actual,
    debugLogger: {
      log: vi.fn(),
      warn: vi.fn(),
      error: vi.fn(),
      debug: vi.fn(),
    },
  };
});

describe('IdeIntegrationNudge', () => {
  const defaultProps = {
    ide: {
      name: 'vscode',
      displayName: 'VS Code',
    },
    onComplete: vi.fn(),
  };

  afterEach(() => {
    vi.restoreAllMocks();
    vi.unstubAllEnvs();
  });

  beforeEach(() => {
    vi.mocked(debugLogger.warn).mockImplementation((...args) => {
      if (
        // eslint-disable-next-line no-restricted-syntax
        typeof args[0] === 'string' &&
        /was not wrapped in act/.test(args[0])
      ) {
        return;
      }
    });
    vi.stubEnv('GEMINI_CLI_IDE_SERVER_PORT', '');
    vi.stubEnv('GEMINI_CLI_IDE_WORKSPACE_PATH', '');
  });

  it('renders correctly with default options', async () => {
    const { lastFrame, unmount } = await renderWithProviders(
      <IdeIntegrationNudge {...defaultProps} />,
    );
    const frame = lastFrame();

    expect(frame).toContain('Do you want to connect VS Code to Gemini CLI?');
    expect(frame).toContain('Yes');
    expect(frame).toContain('No (esc)');
    expect(frame).toContain("No, don't ask again");
    unmount();
  });

  it('handles "Yes" selection', async () => {
    const onComplete = vi.fn();
    const { stdin, waitUntilReady, unmount } = await renderWithProviders(
      <IdeIntegrationNudge {...defaultProps} onComplete={onComplete} />,
    );

    // "Yes" is the first option and selected by default usually.
    await act(async () => {
      stdin.write('\r');
    });
    await waitUntilReady();

    expect(onComplete).toHaveBeenCalledWith({
      userSelection: 'yes',
      isExtensionPreInstalled: false,
    });
    unmount();
  });

  it('handles "No" selection', async () => {
    const onComplete = vi.fn();
    const { stdin, waitUntilReady, unmount } = await renderWithProviders(
      <IdeIntegrationNudge {...defaultProps} onComplete={onComplete} />,
    );

    // Navigate down to "No (esc)"
    await act(async () => {
      stdin.write('\u001B[B'); // Down arrow
    });
    await waitUntilReady();

    await act(async () => {
      stdin.write('\r'); // Enter
    });
    await waitUntilReady();

    expect(onComplete).toHaveBeenCalledWith({
      userSelection: 'no',
      isExtensionPreInstalled: false,
    });
    unmount();
  });

  it('handles "Dismiss" selection', async () => {
    const onComplete = vi.fn();
    const { stdin, waitUntilReady, unmount } = await renderWithProviders(
      <IdeIntegrationNudge {...defaultProps} onComplete={onComplete} />,
    );

    // Navigate down to "No, don't ask again"
    await act(async () => {
      stdin.write('\u001B[B'); // Down arrow
    });
    await waitUntilReady();

    await act(async () => {
      stdin.write('\u001B[B'); // Down arrow
    });
    await waitUntilReady();

    await act(async () => {
      stdin.write('\r'); // Enter
    });
    await waitUntilReady();

    expect(onComplete).toHaveBeenCalledWith({
      userSelection: 'dismiss',
      isExtensionPreInstalled: false,
    });
    unmount();
  });

  it('handles Escape key press', async () => {
    const onComplete = vi.fn();
    const { stdin, waitUntilReady, unmount } = await renderWithProviders(
      <IdeIntegrationNudge {...defaultProps} onComplete={onComplete} />,
    );

    // Press Escape
    await act(async () => {
      stdin.write('\u001B');
    });
    // Escape key has a timeout in KeypressContext, so we need to wrap waitUntilReady in act
    await act(async () => {
      await waitUntilReady();
    });

    expect(onComplete).toHaveBeenCalledWith({
      userSelection: 'no',
      isExtensionPreInstalled: false,
    });
    unmount();
  });

  it('displays correct text and handles selection when extension is pre-installed', async () => {
    vi.stubEnv('GEMINI_CLI_IDE_SERVER_PORT', '1234');
    vi.stubEnv('GEMINI_CLI_IDE_WORKSPACE_PATH', '/tmp');

    const onComplete = vi.fn();
    const { lastFrame, stdin, waitUntilReady, unmount } =
      await renderWithProviders(
        <IdeIntegrationNudge {...defaultProps} onComplete={onComplete} />,
      );

    const frame = lastFrame();

    expect(frame).toContain(
      'If you select Yes, the CLI will have access to your open files',
    );
    expect(frame).not.toContain("we'll install an extension");

    // Select "Yes"
    await act(async () => {
      stdin.write('\r');
    });
    await waitUntilReady();

    expect(onComplete).toHaveBeenCalledWith({
      userSelection: 'yes',
      isExtensionPreInstalled: true,
    });
    unmount();
  });
});
