import { afterEach, describe, expect, it, vi } from 'vitest'

import { api } from './api'

describe('api helper', () => {
  afterEach(() => {
    vi.restoreAllMocks()
  })

  it('returns parsed json when content-type is json', async () => {
    const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
      new Response(JSON.stringify({ ok: true }), {
        status: 200,
        headers: { 'content-type': 'application/json' },
      }),
    )

    const res = await api<{ ok: boolean }>('/api/healthz')
    expect(res.ok).toBe(true)
    expect(fetchMock).toHaveBeenCalledWith('/api/healthz', { credentials: 'include' })
  })

  it('parses json from text payload when response header is not json', async () => {
    vi.spyOn(globalThis, 'fetch').mockResolvedValue(
      new Response('{"value":42}', {
        status: 200,
        headers: { 'content-type': 'text/plain' },
      }),
    )

    const res = await api<{ value: number }>('/api/text-json')
    expect(res.value).toBe(42)
  })

  it('returns raw text when text is not json', async () => {
    vi.spyOn(globalThis, 'fetch').mockResolvedValue(
      new Response('hello', {
        status: 200,
        headers: { 'content-type': 'text/plain' },
      }),
    )

    const res = await api<string>('/api/text')
    expect(res).toBe('hello')
  })

  it('throws server message when response is not ok', async () => {
    vi.spyOn(globalThis, 'fetch').mockResolvedValue(
      new Response('invalid credentials', {
        status: 401,
        headers: { 'content-type': 'text/plain' },
      }),
    )

    await expect(api('/api/login')).rejects.toThrow('invalid credentials')
  })
})
