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

import { getJson, setUnauthorizedHandler } from '@/services/httpClient'

const jsonHeaders = {
  headers: {
    get: (name: string) => (name.toLowerCase() === 'content-type' ? 'application/json' : null),
  },
}

function mockJsonResponse(payload: unknown, status = 200): Response {
  return {
    ok: status >= 200 && status < 300,
    status,
    json: async () => payload,
    text: async () => JSON.stringify(payload),
    ...jsonHeaders,
  } as Response
}

describe('httpClient auth integration', () => {
  beforeEach(() => {
    vi.restoreAllMocks()
    sessionStorage.clear()
    localStorage.clear()
    setUnauthorizedHandler(null)
  })

  it('adds Authorization when a session token exists', async () => {
    const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(mockJsonResponse({ ok: true }))
    sessionStorage.setItem('th_hotel_access_token', 'session-token')

    await getJson('/api/reservation/orders')

    expect(fetchMock).toHaveBeenCalledWith(
      '/api/reservation/orders',
      expect.objectContaining({
        headers: expect.objectContaining({
          Authorization: 'Bearer session-token',
        }),
      }),
    )
  })

  it('runs the unauthorized handler for invalid auth sessions', async () => {
    const unauthorizedHandler = vi.fn()
    setUnauthorizedHandler(unauthorizedHandler)
    sessionStorage.setItem('th_hotel_access_token', 'expired-token')
    vi.spyOn(globalThis, 'fetch').mockResolvedValue(
      mockJsonResponse(
        {
          error_code: 'AUTH_SESSION_INVALID',
          message: '登录已失效。',
        },
        401,
      ),
    )

    await expect(getJson('/api/auth/me')).rejects.toMatchObject({
      status: 401,
    })

    expect(unauthorizedHandler).toHaveBeenCalledOnce()
  })
})
