import { describe, expect, it } from 'vitest';
import {
  loadSettings,
  saveSettings,
  setActiveProvider,
  getActiveProviderConfig,
  isProviderConfigured,
  clearSettings,
  getProviderDisplayName,
  getAvailableModels,
  getProviderCapabilities,
} from '../../src/core/llm/settings-service';

describe('loadSettings', () => {
  it('returns defaults when nothing is stored', () => {
    const settings = loadSettings();
    expect(settings.activeProvider).toBeDefined();
    expect(settings.openai).toBeDefined();
    expect(settings.ollama).toBeDefined();
  });

  it('merges stored values with defaults', () => {
    sessionStorage.setItem(
      'gitnexus-llm-settings',
      JSON.stringify({
        activeProvider: 'ollama',
        ollama: { model: 'qwen3-coder:30b' },
      }),
    );

    const settings = loadSettings();
    expect(settings.activeProvider).toBe('ollama');
    expect(settings.ollama.model).toBe('qwen3-coder:30b');
    // Should still have other provider defaults
    expect(settings.openai).toBeDefined();
  });

  it('returns defaults on corrupted JSON', () => {
    sessionStorage.setItem('gitnexus-llm-settings', 'not-json{{{');
    const settings = loadSettings();
    expect(settings.activeProvider).toBeDefined();
  });

  it('migrates legacy localStorage to sessionStorage', () => {
    localStorage.setItem(
      'gitnexus-llm-settings',
      JSON.stringify({
        activeProvider: 'ollama',
        ollama: { model: 'migrated-model' },
      }),
    );

    const settings = loadSettings();
    expect(settings.ollama.model).toBe('migrated-model');
    expect(sessionStorage.getItem('gitnexus-llm-settings')).not.toBeNull();
    expect(localStorage.getItem('gitnexus-llm-settings')).toBeNull();
  });
});

describe('saveSettings / clearSettings', () => {
  it('persists settings to sessionStorage', () => {
    const settings = loadSettings();
    settings.activeProvider = 'anthropic';
    saveSettings(settings);
    expect(loadSettings().activeProvider).toBe('anthropic');
  });

  it('clearSettings removes settings from both storages', () => {
    saveSettings({ ...loadSettings(), activeProvider: 'anthropic' });
    expect(sessionStorage.getItem('gitnexus-llm-settings')).not.toBeNull();
    clearSettings();
    expect(sessionStorage.getItem('gitnexus-llm-settings')).toBeNull();
    expect(localStorage.getItem('gitnexus-llm-settings')).toBeNull();
  });
});

describe('setActiveProvider', () => {
  it('changes the active provider and persists', () => {
    setActiveProvider('gemini');
    expect(loadSettings().activeProvider).toBe('gemini');
  });
});

describe('getActiveProviderConfig', () => {
  it('returns null for unconfigured providers requiring API keys', () => {
    setActiveProvider('openai');
    expect(getActiveProviderConfig()).toBeNull();
  });

  it('returns config for ollama without API key', () => {
    setActiveProvider('ollama');
    const config = getActiveProviderConfig();
    expect(config).not.toBeNull();
    expect(config!.provider).toBe('ollama');
  });

  it('returns config for openai when API key is set', () => {
    const settings = loadSettings();
    settings.activeProvider = 'openai';
    settings.openai = { ...settings.openai, apiKey: 'sk-test-123' };
    saveSettings(settings);

    const config = getActiveProviderConfig();
    expect(config).not.toBeNull();
    expect(config!.provider).toBe('openai');
  });

  it('returns config for deepseek when API key is set', () => {
    const settings = loadSettings();
    settings.activeProvider = 'deepseek';
    settings.deepseek = { ...settings.deepseek, apiKey: 'sk-deepseek-123' };
    saveSettings(settings);

    const config = getActiveProviderConfig();
    expect(config).not.toBeNull();
    expect(config!.provider).toBe('deepseek');
  });

  it('returns null for openrouter with empty API key', () => {
    const settings = loadSettings();
    settings.activeProvider = 'openrouter';
    settings.openrouter = { ...settings.openrouter, apiKey: '  ' };
    saveSettings(settings);

    expect(getActiveProviderConfig()).toBeNull();
  });
});

describe('isProviderConfigured', () => {
  it('returns false when provider requires API key and none is set', () => {
    // Manually build a clean openai config with no API key
    saveSettings({
      ...loadSettings(),
      activeProvider: 'openai',
      openai: { apiKey: '', model: 'gpt-4o', temperature: 0.1 },
    });
    expect(isProviderConfigured()).toBe(false);
  });

  it('returns true for ollama (no key required)', () => {
    setActiveProvider('ollama');
    expect(isProviderConfigured()).toBe(true);
  });
});

describe('getProviderDisplayName', () => {
  it('returns human-readable names', () => {
    expect(getProviderDisplayName('openai')).toBe('OpenAI');
    expect(getProviderDisplayName('azure-openai')).toBe('Azure OpenAI');
    expect(getProviderDisplayName('gemini')).toBe('Google Gemini');
    expect(getProviderDisplayName('anthropic')).toBe('Anthropic');
    expect(getProviderDisplayName('ollama')).toBe('Ollama (Local)');
    expect(getProviderDisplayName('openrouter')).toBe('OpenRouter');
    expect(getProviderDisplayName('deepseek')).toBe('DeepSeek');
  });
});

describe('getAvailableModels', () => {
  it('returns models for known providers', () => {
    expect(getAvailableModels('openai').length).toBeGreaterThan(0);
    expect(getAvailableModels('ollama').length).toBeGreaterThan(0);
    expect(getAvailableModels('anthropic')).toContain('claude-sonnet-4-20250514');
    expect(getAvailableModels('deepseek')).toContain('deepseek-v4-flash');
  });

  it('returns empty array for unknown provider', () => {
    expect(getAvailableModels('unknown' as any)).toEqual([]);
  });
});

describe('getProviderCapabilities', () => {
  it('enables transcript replay only for providers that require it', () => {
    expect(getProviderCapabilities('deepseek').preserveAssistantTranscript).toBe(true);
    expect(getProviderCapabilities('openai').preserveAssistantTranscript).toBe(false);
    expect(getProviderCapabilities('anthropic').preserveAssistantTranscript).toBe(false);
  });
});
