import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import {
  createLocalOllamaProvider,
  getAvailableProviders,
  DEFAULT_PROVIDERS,
} from '../registry.js';
import type { ProviderConfig } from '../types.js';

describe('getAvailableProviders', () => {
  const saved: Record<string, string | undefined> = {};

  beforeEach(() => {
    // Save and clear all default provider env vars
    for (const p of DEFAULT_PROVIDERS) {
      const key = p.apiKeyEnv!;
      saved[key] = process.env[key];
      delete process.env[key];
    }
  });

  afterEach(() => {
    // Restore original env
    for (const [key, val] of Object.entries(saved)) {
      if (val === undefined) {
        delete process.env[key];
      } else {
        process.env[key] = val;
      }
    }
  });

  it('returns empty array when no API keys are set', () => {
    expect(getAvailableProviders()).toEqual([]);
  });

  it('returns only providers with API keys set', () => {
    process.env.GROQ_API_KEY = 'gsk_test';
    const result = getAvailableProviders();
    expect(result).toHaveLength(1);
    expect(result[0]!.name).toBe('groq');
  });

  it('returns multiple providers when multiple keys are set', () => {
    process.env.GROQ_API_KEY = 'gsk_test';
    process.env.CEREBRAS_API_KEY = 'csk_test';
    const result = getAvailableProviders();
    expect(result).toHaveLength(2);
    const names = result.map(p => p.name);
    expect(names).toContain('groq');
    expect(names).toContain('cerebras');
  });

  it('excludes providers with empty string API key', () => {
    process.env.GROQ_API_KEY = '';
    expect(getAvailableProviders()).toEqual([]);
  });

  it('works with custom provider list', () => {
    const custom: ProviderConfig[] = [
      {
        name: 'custom',
        baseUrl: 'https://example.com/v1',
        apiKeyEnv: 'CUSTOM_TEST_KEY',
        rpmLimit: 10,
        tpmLimit: 0,
        models: [],
      },
    ];
    expect(getAvailableProviders(custom)).toEqual([]);

    process.env.CUSTOM_TEST_KEY = 'test';
    expect(getAvailableProviders(custom)).toHaveLength(1);
    delete process.env.CUSTOM_TEST_KEY;
  });

  it('includes local providers that do not require API keys', () => {
    const local = createLocalOllamaProvider(['qwen2.5-coder:7b']);
    const result = getAvailableProviders([local]);
    expect(result).toHaveLength(1);
    expect(result[0]!.name).toBe('local-ollama');
  });

  it('infers local ollama model metadata for routing', () => {
    const local = createLocalOllamaProvider(['qwen2.5-coder:7b', 'llama3.1:70b']);

    expect(local.baseUrl).toBe('http://localhost:11434/v1');
    expect(local.models).toEqual([
      expect.objectContaining({
        id: 'qwen2.5-coder:7b',
        contextWindow: 32_768,
        speedTier: 1,
        strengths: expect.arrayContaining(['code']),
      }),
      expect.objectContaining({
        id: 'llama3.1:70b',
        contextWindow: 8_192,
        speedTier: 3,
        strengths: expect.arrayContaining(['general']),
      }),
    ]);
  });

  it('DEFAULT_PROVIDERS includes all 4 providers', () => {
    expect(DEFAULT_PROVIDERS).toHaveLength(4);
    const names = DEFAULT_PROVIDERS.map(p => p.name);
    expect(names).toEqual(['groq', 'openrouter', 'together', 'cerebras']);
  });

  it('OpenRouter provider has recommended extra headers', () => {
    const openrouter = DEFAULT_PROVIDERS.find(p => p.name === 'openrouter');
    expect(openrouter?.extraHeaders).toBeDefined();
    expect(openrouter?.extraHeaders?.['HTTP-Referer']).toBeDefined();
    expect(openrouter?.extraHeaders?.['X-Title']).toBeDefined();
  });
});
