import { describe, it, expect, vi, beforeEach } from 'vitest'
import { render, screen, waitFor } from '@testing-library/react'
import { AuthProvider, useAuth } from '../src/auth'

function Probe() {
  const { status, user, setupNeeded } = useAuth()
  return (
    <div>
      <div>status:{status}</div>
      {setupNeeded && <div>setup-needed</div>}
      {user && <div>user:{user.username}</div>}
    </div>
  )
}

const fetchMock = vi.fn()

beforeEach(() => {
  fetchMock.mockReset()
  vi.stubGlobal('fetch', fetchMock)
})

function jsonOnce(status: number, body: unknown) {
  return new Response(JSON.stringify(body), {
    status,
    headers: { 'content-type': 'application/json' },
  })
}

describe('AuthProvider', () => {
  it('reports setupNeeded when the server has no users', async () => {
    fetchMock.mockResolvedValueOnce(jsonOnce(200, { needed: true }))
    render(
      <AuthProvider>
        <Probe />
      </AuthProvider>
    )
    expect(screen.getByText('status:loading')).toBeTruthy()
    await waitFor(() => expect(screen.getByText('status:setup')).toBeTruthy())
    expect(screen.getByText('setup-needed')).toBeTruthy()
    expect(fetchMock).toHaveBeenCalledWith('/api/setup', expect.anything())
  })

  it('exposes the user when /api/me succeeds', async () => {
    fetchMock
      .mockResolvedValueOnce(jsonOnce(200, { needed: false }))
      .mockResolvedValueOnce(jsonOnce(200, { user: { id: 1, username: 'sam', isAdmin: true } }))
    render(
      <AuthProvider>
        <Probe />
      </AuthProvider>
    )
    await waitFor(() => expect(screen.getByText('status:authenticated')).toBeTruthy())
    expect(screen.getByText('user:sam')).toBeTruthy()
  })

  it('reports unauthenticated when /api/me is 401', async () => {
    fetchMock
      .mockResolvedValueOnce(jsonOnce(200, { needed: false }))
      .mockResolvedValueOnce(jsonOnce(401, { error: 'unauthorized' }))
    render(
      <AuthProvider>
        <Probe />
      </AuthProvider>
    )
    await waitFor(() => expect(screen.getByText('status:unauthenticated')).toBeTruthy())
  })
})
