/**
 * Tests for LLM providers and factory.
 */

import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
import { MockLLMProvider } from '../providers/mock.js';
import { createLLMProvider, _resetLLM } from '../factory.js';

describe('MockLLMProvider', () => {
  let provider: MockLLMProvider;

  beforeEach(() => {
    provider = new MockLLMProvider();
  });

  it('isConfigured returns true', () => {
    expect(provider.isConfigured()).toBe(true);
  });

  it('returns default echo response', async () => {
    const result = await provider.chatCompletion({
      messages: [{ role: 'user', content: 'Hello' }],
    });
    expect(result.content).toContain('Hello');
    expect(result.finishReason).toBe('stop');
  });

  it('returns queued responses', async () => {
    provider.addResponse({
      content: 'Custom response',
      model: 'test-model',
      finishReason: 'stop',
      usage: { promptTokens: 5, completionTokens: 5, totalTokens: 10 },
    });

    const result = await provider.chatCompletion({
      messages: [{ role: 'user', content: 'Hello' }],
    });
    expect(result.content).toBe('Custom response');
  });

  it('tracks calls', async () => {
    const req = { messages: [{ role: 'user' as const, content: 'Test' }] };
    await provider.chatCompletion(req);
    expect(provider.calls).toHaveLength(1);
    expect(provider.calls[0]).toEqual(req);
  });

  it('reset clears calls and responses', async () => {
    provider.addResponse({
      content: 'x',
      model: 'm',
      finishReason: 'stop',
      usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },
    });
    await provider.chatCompletion({ messages: [{ role: 'user', content: 'Test' }] });
    provider.reset();
    expect(provider.calls).toHaveLength(0);
  });
});

describe('createLLMProvider', () => {
  afterEach(() => {
    _resetLLM();
    vi.unstubAllEnvs();
  });

  it('creates mock provider', () => {
    const provider = createLLMProvider('mock');
    expect(provider).toBeInstanceOf(MockLLMProvider);
  });

  it('throws for unknown type', () => {
    expect(() => createLLMProvider('unknown' as 'mock')).toThrow('Unknown LLM_PROVIDER');
  });
});
