import { describe, expect, it } from 'vitest'
import {
  AuthError,
  QuotaExhaustedError,
  RateLimitError,
  TransientError,
  type AIRequest,
} from './index.js'
import { makeMockAdapter, resolveMockDirective, throwForMockDirective } from './mock.js'

describe('mock adapter', () => {
  const baseReq: AIRequest = {
    model: 'TEST',
    messages: [{ role: 'user', content: 'ping' }],
  }

  it('resolves model-string directives', () => {
    expect(resolveMockDirective({ ...baseReq, model: 'TEST-RATELIMIT' })?.kind).toBe('RATELIMIT')
    expect(resolveMockDirective({ ...baseReq, model: 'TEST-QUOTA' })?.kind).toBe('QUOTA')
    expect(resolveMockDirective({ ...baseReq, model: 'TEST-AUTH' })?.kind).toBe('AUTH')
    expect(resolveMockDirective(baseReq)).toBeNull()
  })

  it('prefers input sentinel over model directive', () => {
    const req: AIRequest = {
      model: 'TEST-RATELIMIT',
      messages: [{ role: 'user', content: 'hello @@MOCK:AUTH@@' }],
    }
    expect(resolveMockDirective(req)?.kind).toBe('AUTH')
  })

  it('returns OK response by default with token-only usage', async () => {
    const adapter = makeMockAdapter()
    const result = await adapter.call(baseReq)
    expect(result.content).toBe('[TEST] mock ok')
    expect(result.usage).toEqual({ promptTokens: 1, completionTokens: 1 })
    expect(Object.keys(result.usage)).toEqual(['promptTokens', 'completionTokens'])
    // mock maps no image content → honest false (not a lie-by-true on a fixture
    // that does nothing image-related); the flag is still readable through the seam.
    expect(adapter.supportsImage).toBe(false)
  })

  it('simulates retryable and non-retryable errors on command', async () => {
    const adapter = makeMockAdapter()
    await expect(
      adapter.call({ ...baseReq, model: 'TEST-RATELIMIT' }),
    ).rejects.toBeInstanceOf(RateLimitError)
    await expect(adapter.call({ ...baseReq, model: 'TEST-QUOTA' })).rejects.toBeInstanceOf(
      QuotaExhaustedError,
    )
    await expect(adapter.call({ ...baseReq, model: 'TEST-AUTH' })).rejects.toBeInstanceOf(AuthError)
    await expect(adapter.call({ ...baseReq, model: 'TEST-TRANSIENT' })).rejects.toBeInstanceOf(
      TransientError,
    )
    expect(new RateLimitError('x').retryable).toBe(true)
    expect(new AuthError('x').retryable).toBe(false)
  })

  it('throwForMockDirective maps ERROR to FatalError', () => {
    expect(() => throwForMockDirective('ERROR')).toThrow()
  })
})
