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

import * as fs from 'node:fs';
import * as path from 'node:path';
import {
  beforeAll,
  afterAll,
  beforeEach,
  describe,
  expect,
  it,
  vi,
  afterEach,
} from 'vitest';

import { createExtension } from '../test-utils/createExtension.js';
import { ExtensionManager } from './extension-manager.js';
import { themeManager, DEFAULT_THEME } from '../ui/themes/theme-manager.js';
import {
  GEMINI_DIR,
  type Config,
  tmpdir,
  NoopSandboxManager,
} from '@google/gemini-cli-core';
import { createTestMergedSettings, SettingScope } from './settings.js';

describe('ExtensionManager theme loading', () => {
  let extensionManager: ExtensionManager;
  let userExtensionsDir: string;
  let tempHomeDir: string;

  beforeAll(async () => {
    tempHomeDir = await fs.promises.mkdtemp(
      path.join(tmpdir(), 'gemini-cli-test-'),
    );
  });

  afterAll(async () => {
    if (tempHomeDir) {
      await fs.promises.rm(tempHomeDir, { recursive: true, force: true });
    }
  });

  beforeEach(() => {
    process.env['GEMINI_CLI_HOME'] = tempHomeDir;
    userExtensionsDir = path.join(tempHomeDir, GEMINI_DIR, 'extensions');
    // Ensure userExtensionsDir is clean for each test
    fs.rmSync(userExtensionsDir, { recursive: true, force: true });
    fs.mkdirSync(userExtensionsDir, { recursive: true });

    extensionManager = new ExtensionManager({
      settings: createTestMergedSettings({
        experimental: { extensionConfig: true },
        security: { blockGitExtensions: false },
        admin: { extensions: { enabled: true }, mcp: { enabled: true } },
      }),
      requestConsent: async () => true,
      requestSetting: async () => '',
      workspaceDir: tempHomeDir,
      enabledExtensionOverrides: [],
    });
    vi.clearAllMocks();
    themeManager.clearExtensionThemes();
    themeManager.loadCustomThemes({});
    themeManager.setActiveTheme(DEFAULT_THEME.name);
  });

  afterEach(() => {
    delete process.env['GEMINI_CLI_HOME'];
  });

  it('should register themes from an extension when started', async () => {
    const registerSpy = vi.spyOn(themeManager, 'registerExtensionThemes');
    createExtension({
      extensionsDir: userExtensionsDir,
      name: 'my-theme-extension',
      themes: [
        {
          name: 'My-Awesome-Theme',
          type: 'custom',
          text: {
            primary: '#FF00FF',
          },
        },
      ],
    });

    await extensionManager.loadExtensions();

    // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
    const mockConfig = {
      getEnableExtensionReloading: () => false,
      getMcpClientManager: () => ({
        startExtension: vi.fn().mockResolvedValue(undefined),
      }),
      getGeminiClient: () => ({
        isInitialized: () => false,
        updateSystemInstruction: vi.fn(),
        setTools: vi.fn(),
      }),
      getHookSystem: () => undefined,
      getWorkingDir: () => tempHomeDir,
      shouldLoadMemoryFromIncludeDirectories: () => false,
      getDebugMode: () => false,
      getFileExclusions: () => ({
        isIgnored: () => false,
      }),
      getGeminiMdFilePaths: () => [],
      getMcpServers: () => ({}),
      getAllowedMcpServers: () => [],
      getSanitizationConfig: () => ({
        allowedEnvironmentVariables: [],
        blockedEnvironmentVariables: [],
        enableEnvironmentVariableRedaction: false,
      }),
      getShellExecutionConfig: () => ({
        terminalWidth: 80,
        terminalHeight: 24,
        showColor: false,
        pager: 'cat',
        sandboxManager: new NoopSandboxManager(),
        sanitizationConfig: {
          allowedEnvironmentVariables: [],
          blockedEnvironmentVariables: [],
          enableEnvironmentVariableRedaction: false,
        },
      }),
      getToolRegistry: () => ({
        getTools: () => [],
      }),
      getProxy: () => undefined,
      getFileService: () => ({
        findFiles: async () => [],
      }),
      getExtensionLoader: () => ({
        getExtensions: () => [],
      }),
      isTrustedFolder: () => true,
      getImportFormat: () => 'tree',
      reloadSkills: vi.fn(),
    } as unknown as Config;

    await extensionManager.start(mockConfig);

    expect(registerSpy).toHaveBeenCalledWith('my-theme-extension', [
      {
        name: 'My-Awesome-Theme',
        type: 'custom',
        text: {
          primary: '#FF00FF',
        },
      },
    ]);
  });

  it('should revert to default theme when extension is stopped', async () => {
    const extensionName = 'my-theme-extension';
    const themeName = 'My-Awesome-Theme';
    const namespacedThemeName = `${themeName} (${extensionName})`;

    createExtension({
      extensionsDir: userExtensionsDir,
      name: extensionName,
      themes: [
        {
          name: themeName,
          type: 'custom',
          text: {
            primary: '#FF00FF',
          },
        },
      ],
    });

    await extensionManager.loadExtensions();

    // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
    const mockConfig = {
      getWorkingDir: () => tempHomeDir,
      shouldLoadMemoryFromIncludeDirectories: () => false,
      getWorkspaceContext: () => ({
        getDirectories: () => [],
      }),
      getDebugMode: () => false,
      getFileService: () => ({
        findFiles: async () => [],
      }),
      getExtensionLoader: () => ({
        getExtensions: () => [],
      }),
      isTrustedFolder: () => true,
      getImportFormat: () => 'tree',
      getFileFilteringOptions: () => ({
        respectGitIgnore: true,
        respectGeminiIgnore: true,
      }),
      getDiscoveryMaxDirs: () => 200,
      getMemoryBoundaryMarkers: () => ['.git'],
      getMcpClientManager: () => ({
        getMcpInstructions: () => '',
        startExtension: vi.fn().mockResolvedValue(undefined),
        stopExtension: vi.fn().mockResolvedValue(undefined),
      }),
      setUserMemory: vi.fn(),
      setGeminiMdFileCount: vi.fn(),
      setGeminiMdFilePaths: vi.fn(),
      getEnableExtensionReloading: () => true,
      getGeminiClient: () => ({
        isInitialized: () => false,
        updateSystemInstruction: vi.fn(),
        setTools: vi.fn(),
      }),
      getHookSystem: () => undefined,
      getProxy: () => undefined,
      getAgentRegistry: () => ({
        reload: vi.fn().mockResolvedValue(undefined),
      }),
      reloadSkills: vi.fn(),
    } as unknown as Config;

    await extensionManager.start(mockConfig);

    // Set the active theme to the one from the extension
    themeManager.setActiveTheme(namespacedThemeName);
    expect(themeManager.getActiveTheme().name).toBe(namespacedThemeName);

    // Stop the extension
    await extensionManager.disableExtension(extensionName, SettingScope.User);

    // Check that the active theme has reverted to the default
    expect(themeManager.getActiveTheme().name).toBe(DEFAULT_THEME.name);
  });
});
