import { http, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'
import { describe, it, expect, beforeAll, afterEach, afterAll } from 'vitest'
import { listProviders, createProvider, updateProvider, deleteProvider } from '@/api/providers'

const mockProviders = [
  {
    id: 'prov-1',
    name: 'OpenAI',
    api_key: 'sk-xxx',
    base_url: 'https://api.openai.com',
    protocol: 'openai',
    enabled: true,
    created_at: '2025-01-01T00:00:00Z',
    updated_at: '2025-01-01T00:00:00Z',
  },
  {
    id: 'prov-2',
    name: 'Anthropic',
    api_key: 'sk-yyy',
    base_url: 'https://api.anthropic.com',
    protocol: 'anthropic',
    enabled: false,
    created_at: '2025-01-02T00:00:00Z',
    updated_at: '2025-01-02T00:00:00Z',
  },
]

describe('providers API', () => {
  const server = setupServer()

  beforeAll(() => server.listen({ onUnhandledRequest: 'bypass' }))
  afterEach(() => server.resetHandlers())
  afterAll(() => server.close())

  describe('listProviders', () => {
    it('returns array of Provider objects with camelCase keys', async () => {
      server.use(
        http.get('http://localhost:3000/api/providers', () => {
          return HttpResponse.json(mockProviders)
        })
      )

      const result = await listProviders()

      expect(result).toEqual([
        {
          id: 'prov-1',
          name: 'OpenAI',
          apiKey: 'sk-xxx',
          baseUrl: 'https://api.openai.com',
          protocol: 'openai',
          enabled: true,
          createdAt: '2025-01-01T00:00:00Z',
          updatedAt: '2025-01-01T00:00:00Z',
        },
        {
          id: 'prov-2',
          name: 'Anthropic',
          apiKey: 'sk-yyy',
          baseUrl: 'https://api.anthropic.com',
          protocol: 'anthropic',
          enabled: false,
          createdAt: '2025-01-02T00:00:00Z',
          updatedAt: '2025-01-02T00:00:00Z',
        },
      ])
    })
  })

  describe('createProvider', () => {
    it('sends POST with correct body and returns provider', async () => {
      let receivedMethod: string | null = null
      let receivedBody: Record<string, unknown> | null = null

      server.use(
        http.post('http://localhost:3000/api/providers', async ({ request }) => {
          receivedMethod = request.method
          receivedBody = (await request.json()) as Record<string, unknown>
          return HttpResponse.json(mockProviders[0])
        })
      )

      const input = {
        id: 'prov-1',
        name: 'OpenAI',
        apiKey: 'sk-xxx',
        baseUrl: 'https://api.openai.com',
        enabled: true,
      }

      const result = await createProvider(input)

      expect(receivedMethod).toBe('POST')
      expect(receivedBody).toEqual({
        id: 'prov-1',
        name: 'OpenAI',
        api_key: 'sk-xxx',
        base_url: 'https://api.openai.com',
        enabled: true,
      })
      expect(result).toEqual({
        id: 'prov-1',
        name: 'OpenAI',
        apiKey: 'sk-xxx',
        baseUrl: 'https://api.openai.com',
        protocol: 'openai',
        enabled: true,
        createdAt: '2025-01-01T00:00:00Z',
        updatedAt: '2025-01-01T00:00:00Z',
      })
    })
  })

  describe('updateProvider', () => {
    it('sends PUT with correct body and returns provider', async () => {
      let receivedMethod: string | null = null
      let receivedUrl: string | null = null
      let receivedBody: Record<string, unknown> | null = null

      server.use(
        http.put('http://localhost:3000/api/providers/:id', async ({ request }) => {
          receivedMethod = request.method
          receivedUrl = new URL(request.url).pathname
          receivedBody = (await request.json()) as Record<string, unknown>
          return HttpResponse.json({
            ...mockProviders[0],
            name: 'Updated',
            api_key: 'sk-updated',
          })
        })
      )

      const result = await updateProvider('prov-1', {
        name: 'Updated',
        apiKey: 'sk-updated',
      })

      expect(receivedMethod).toBe('PUT')
      expect(receivedUrl).toBe('/api/providers/prov-1')
      expect(receivedBody).toEqual({
        name: 'Updated',
        api_key: 'sk-updated',
      })
      expect(result.name).toBe('Updated')
      expect(result.apiKey).toBe('sk-updated')
    })
  })

  describe('deleteProvider', () => {
    it('sends DELETE and returns void', async () => {
      let receivedMethod: string | null = null
      let receivedUrl: string | null = null

      server.use(
        http.delete('http://localhost:3000/api/providers/:id', ({ request }) => {
          receivedMethod = request.method
          receivedUrl = new URL(request.url).pathname
          return new HttpResponse(null, { status: 204 })
        })
      )

      const result = await deleteProvider('prov-1')

      expect(receivedMethod).toBe('DELETE')
      expect(receivedUrl).toBe('/api/providers/prov-1')
      expect(result).toBeUndefined()
    })
  })
})
