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

import { describe, it, expect, vi, afterEach, beforeEach } from 'vitest';
import { detectIde, IDE_DEFINITIONS } from './detect-ide.js';

beforeEach(() => {
  // Ensure Antigravity detection doesn't interfere with other tests
  vi.stubEnv('ANTIGRAVITY_CLI_ALIAS', '');
});

describe('detectIde', () => {
  const ideProcessInfo = { pid: 123, command: 'some/path/to/code' };
  const ideProcessInfoNoCode = { pid: 123, command: 'some/path/to/fork' };

  beforeEach(() => {
    // Ensure these env vars don't leak from the host environment
    vi.stubEnv('ANTIGRAVITY_CLI_ALIAS', '');
    vi.stubEnv('TERM_PROGRAM', '');
    vi.stubEnv('CURSOR_TRACE_ID', '');
    vi.stubEnv('CODESPACES', '');
    vi.stubEnv('VSCODE_IPC_HOOK_CLI', '');
    vi.stubEnv('EDITOR_IN_CLOUD_SHELL', '');
    vi.stubEnv('CLOUD_SHELL', '');
    vi.stubEnv('TERM_PRODUCT', '');
    vi.stubEnv('MONOSPACE_ENV', '');
    vi.stubEnv('REPLIT_USER', '');
    vi.stubEnv('POSITRON', '');
    vi.stubEnv('__COG_BASHRC_SOURCED', '');
    vi.stubEnv('TERMINAL_EMULATOR', '');
  });

  afterEach(() => {
    vi.unstubAllEnvs();
    // Clear Cursor-specific environment variables that might interfere with tests
    delete process.env['CURSOR_TRACE_ID'];
  });

  it('should return undefined if TERM_PROGRAM is not vscode', () => {
    vi.stubEnv('TERM_PROGRAM', '');
    expect(detectIde(ideProcessInfo)).toBeUndefined();
  });

  it('should detect Devin', () => {
    vi.stubEnv('TERM_PROGRAM', 'vscode');
    vi.stubEnv('__COG_BASHRC_SOURCED', '1');
    expect(detectIde(ideProcessInfo)).toBe(IDE_DEFINITIONS.devin);
  });

  it('should detect Replit', () => {
    vi.stubEnv('TERM_PROGRAM', 'vscode');
    vi.stubEnv('REPLIT_USER', 'testuser');
    expect(detectIde(ideProcessInfo)).toBe(IDE_DEFINITIONS.replit);
  });

  it('should detect Cursor', () => {
    vi.stubEnv('TERM_PROGRAM', 'vscode');
    vi.stubEnv('CURSOR_TRACE_ID', 'some-id');
    expect(detectIde(ideProcessInfo)).toBe(IDE_DEFINITIONS.cursor);
  });

  it('should detect Codespaces', () => {
    vi.stubEnv('TERM_PROGRAM', 'vscode');
    vi.stubEnv('CODESPACES', 'true');
    vi.stubEnv('CURSOR_TRACE_ID', '');
    expect(detectIde(ideProcessInfo)).toBe(IDE_DEFINITIONS.codespaces);
  });

  it('should detect Cloud Shell via EDITOR_IN_CLOUD_SHELL', () => {
    vi.stubEnv('TERM_PROGRAM', 'vscode');
    vi.stubEnv('EDITOR_IN_CLOUD_SHELL', 'true');
    vi.stubEnv('CURSOR_TRACE_ID', '');
    expect(detectIde(ideProcessInfo)).toBe(IDE_DEFINITIONS.cloudshell);
  });

  it('should detect Cloud Shell via CLOUD_SHELL', () => {
    vi.stubEnv('TERM_PROGRAM', 'vscode');
    vi.stubEnv('CLOUD_SHELL', 'true');
    vi.stubEnv('CURSOR_TRACE_ID', '');
    expect(detectIde(ideProcessInfo)).toBe(IDE_DEFINITIONS.cloudshell);
  });

  it('should detect Trae', () => {
    vi.stubEnv('TERM_PROGRAM', 'vscode');
    vi.stubEnv('TERM_PRODUCT', 'Trae');
    vi.stubEnv('CURSOR_TRACE_ID', '');
    expect(detectIde(ideProcessInfo)).toBe(IDE_DEFINITIONS.trae);
  });

  it('should detect Firebase Studio via MONOSPACE_ENV', () => {
    vi.stubEnv('TERM_PROGRAM', 'vscode');
    vi.stubEnv('MONOSPACE_ENV', 'true');
    vi.stubEnv('CURSOR_TRACE_ID', '');
    expect(detectIde(ideProcessInfo)).toBe(IDE_DEFINITIONS.firebasestudio);
  });

  it('should detect VSCode when no other IDE is detected and command includes "code"', () => {
    vi.stubEnv('TERM_PROGRAM', 'vscode');
    vi.stubEnv('MONOSPACE_ENV', '');
    vi.stubEnv('CURSOR_TRACE_ID', '');
    vi.stubEnv('POSITRON', '');
    expect(detectIde(ideProcessInfo)).toBe(IDE_DEFINITIONS.vscode);
  });

  it('should detect VSCodeFork when no other IDE is detected and command does not include "code"', () => {
    vi.stubEnv('TERM_PROGRAM', 'vscode');
    vi.stubEnv('MONOSPACE_ENV', '');
    vi.stubEnv('CURSOR_TRACE_ID', '');
    vi.stubEnv('POSITRON', '');
    expect(detectIde(ideProcessInfoNoCode)).toBe(IDE_DEFINITIONS.vscodefork);
  });

  it('should detect positron when POSITRON is set', () => {
    vi.stubEnv('TERM_PROGRAM', 'vscode');
    vi.stubEnv('MONOSPACE_ENV', '');
    vi.stubEnv('CURSOR_TRACE_ID', '');
    vi.stubEnv('POSITRON', '1');
    expect(detectIde(ideProcessInfoNoCode)).toBe(IDE_DEFINITIONS.positron);
  });

  it('should detect AntiGravity', () => {
    vi.stubEnv('TERM_PROGRAM', 'vscode');
    vi.stubEnv('POSITRON', '');
    vi.stubEnv('ANTIGRAVITY_CLI_ALIAS', 'agy');
    expect(detectIde(ideProcessInfo)).toBe(IDE_DEFINITIONS.antigravity);
  });

  it('should detect Sublime Text', () => {
    vi.stubEnv('TERM_PROGRAM', 'sublime');
    vi.stubEnv('ANTIGRAVITY_CLI_ALIAS', '');
    expect(detectIde(ideProcessInfo)).toBe(IDE_DEFINITIONS.sublimetext);
  });

  it('should prioritize Antigravity over Sublime Text', () => {
    vi.stubEnv('TERM_PROGRAM', 'sublime');
    vi.stubEnv('ANTIGRAVITY_CLI_ALIAS', 'agy');
    expect(detectIde(ideProcessInfo)).toBe(IDE_DEFINITIONS.antigravity);
  });

  it('should detect Zed via ZED_SESSION_ID', () => {
    vi.stubEnv('ZED_SESSION_ID', 'test-session-id');
    expect(detectIde(ideProcessInfo)).toBe(IDE_DEFINITIONS.zed);
  });

  it('should detect Zed via TERM_PROGRAM', () => {
    vi.stubEnv('TERM_PROGRAM', 'Zed');
    expect(detectIde(ideProcessInfo)).toBe(IDE_DEFINITIONS.zed);
  });

  it('should detect XCode via XCODE_VERSION_ACTUAL', () => {
    vi.stubEnv('XCODE_VERSION_ACTUAL', '1500');
    expect(detectIde(ideProcessInfo)).toBe(IDE_DEFINITIONS.xcode);
  });

  it('should detect JetBrains IDE via TERMINAL_EMULATOR', () => {
    vi.stubEnv('TERMINAL_EMULATOR', 'JetBrains-JediTerm');
    expect(detectIde(ideProcessInfo)).toBe(IDE_DEFINITIONS.jetbrains);
  });

  describe('JetBrains IDE detection via command', () => {
    beforeEach(() => {
      vi.stubEnv('TERMINAL_EMULATOR', 'JetBrains-JediTerm');
    });

    it.each([
      [
        'IntelliJ IDEA',
        '/Applications/IntelliJ IDEA.app',
        IDE_DEFINITIONS.intellijidea,
      ],
      ['WebStorm', '/Applications/WebStorm.app', IDE_DEFINITIONS.webstorm],
      ['PyCharm', '/Applications/PyCharm.app', IDE_DEFINITIONS.pycharm],
      ['GoLand', '/Applications/GoLand.app', IDE_DEFINITIONS.goland],
      [
        'Android Studio',
        '/Applications/Android Studio.app',
        IDE_DEFINITIONS.androidstudio,
      ],
      ['CLion', '/Applications/CLion.app', IDE_DEFINITIONS.clion],
      ['RustRover', '/Applications/RustRover.app', IDE_DEFINITIONS.rustrover],
      ['DataGrip', '/Applications/DataGrip.app', IDE_DEFINITIONS.datagrip],
      ['PhpStorm', '/Applications/PhpStorm.app', IDE_DEFINITIONS.phpstorm],
    ])('should detect %s via command', (_name, command, expectedIde) => {
      const processInfo = { pid: 123, command };
      expect(detectIde(processInfo)).toBe(expectedIde);
    });
  });

  it('should return generic JetBrains when command does not match specific IDE', () => {
    vi.stubEnv('TERMINAL_EMULATOR', 'JetBrains-JediTerm');
    const genericProcessInfo = {
      pid: 123,
      command: '/Applications/SomeJetBrainsApp.app',
    };
    expect(detectIde(genericProcessInfo)).toBe(IDE_DEFINITIONS.jetbrains);
  });

  it('should prioritize JetBrains detection over VS Code when TERMINAL_EMULATOR is set', () => {
    vi.stubEnv('TERM_PROGRAM', 'vscode');
    vi.stubEnv('TERMINAL_EMULATOR', 'JetBrains-JediTerm');
    expect(detectIde(ideProcessInfo)).toBe(IDE_DEFINITIONS.jetbrains);
  });
});

describe('detectIde with ideInfoFromFile', () => {
  const ideProcessInfo = { pid: 123, command: 'some/path/to/code' };

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

  beforeEach(() => {
    vi.stubEnv('ANTIGRAVITY_CLI_ALIAS', '');
    vi.stubEnv('TERM_PROGRAM', '');
    vi.stubEnv('CURSOR_TRACE_ID', '');
    vi.stubEnv('CODESPACES', '');
    vi.stubEnv('VSCODE_IPC_HOOK_CLI', '');
    vi.stubEnv('EDITOR_IN_CLOUD_SHELL', '');
    vi.stubEnv('CLOUD_SHELL', '');
    vi.stubEnv('TERM_PRODUCT', '');
    vi.stubEnv('MONOSPACE_ENV', '');
    vi.stubEnv('REPLIT_USER', '');
    vi.stubEnv('POSITRON', '');
    vi.stubEnv('__COG_BASHRC_SOURCED', '');
    vi.stubEnv('TERMINAL_EMULATOR', '');
  });

  it('should use the name and displayName from the file', () => {
    const ideInfoFromFile = {
      name: 'custom-ide',
      displayName: 'Custom IDE',
    };
    expect(detectIde(ideProcessInfo, ideInfoFromFile)).toEqual(ideInfoFromFile);
  });

  it('should fall back to env detection if name is missing', () => {
    const ideInfoFromFile = { displayName: 'Custom IDE' };
    vi.stubEnv('TERM_PROGRAM', 'vscode');
    vi.stubEnv('CURSOR_TRACE_ID', '');
    vi.stubEnv('POSITRON', '');
    expect(detectIde(ideProcessInfo, ideInfoFromFile)).toBe(
      IDE_DEFINITIONS.vscode,
    );
  });

  it('should fall back to env detection if displayName is missing', () => {
    const ideInfoFromFile = { name: 'custom-ide' };
    vi.stubEnv('TERM_PROGRAM', 'vscode');
    vi.stubEnv('CURSOR_TRACE_ID', '');
    vi.stubEnv('POSITRON', '');
    expect(detectIde(ideProcessInfo, ideInfoFromFile)).toBe(
      IDE_DEFINITIONS.vscode,
    );
  });
});
