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

afterEach(() => {
  vi.restoreAllMocks()
  delete process.env.API_INTERNAL_URL
  delete process.env.API_URL
  delete process.env.NEXT_PUBLIC_API_URL
})

describe('dashboard API proxy route', () => {
  it('forwards dashboard API requests to the configured API origin', async () => {
    process.env.API_INTERNAL_URL = 'http://api:4000/api/v1'
    const fetchMock = vi.fn(async () => new Response(JSON.stringify({ data: { ok: true } }), {
      status: 200,
      headers: { 'content-type': 'application/json' },
    }))
    Object.defineProperty(globalThis, 'fetch', { configurable: true, value: fetchMock })

    const { GET } = await import('./route')
    const response = await GET(
      new Request('https://rentaldrivego.ma/dashboard/api/v1/auth/employee/me?fresh=1', {
        headers: { cookie: 'employee_session=token-123' },
      }),
      { params: { path: ['auth', 'employee', 'me'] } },
    )

    expect(fetchMock).toHaveBeenCalledWith(new URL('http://api:4000/api/v1/auth/employee/me?fresh=1'), expect.objectContaining({
      method: 'GET',
      cache: 'no-store',
      headers: expect.any(Headers),
    }))
    const forwardedInit = (fetchMock as any).mock.calls[0][1] as RequestInit
    expect((forwardedInit.headers as Headers).get('cookie')).toBe('employee_session=token-123')
    await expect(response.json()).resolves.toEqual({ data: { ok: true } })
  })

  it('rewrites upstream session cookies for the dashboard host', async () => {
    process.env.API_URL = 'https://api.rentaldrivego.ma'
    const headers = new Headers({ 'content-type': 'application/json' })
    headers.append('set-cookie', 'employee_session=token-123; Path=/; Domain=api.rentaldrivego.ma; HttpOnly; Secure; SameSite=Lax')
    const fetchMock = vi.fn(async () => new Response(JSON.stringify({ data: { employee: { id: 'emp_1' } } }), {
      status: 200,
      headers,
    }))
    Object.defineProperty(globalThis, 'fetch', { configurable: true, value: fetchMock })

    const { POST } = await import('./route')
    const response = await POST(
      new Request('https://rentaldrivego.ma/dashboard/api/v1/auth/employee/login', {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ email: 'owner@example.com', password: 'secret' }),
      }),
      { params: Promise.resolve({ path: ['auth', 'employee', 'login'] }) },
    )

    expect(fetchMock).toHaveBeenCalledWith(new URL('https://api.rentaldrivego.ma/api/v1/auth/employee/login'), expect.objectContaining({
      method: 'POST',
    }))
    expect(response.headers.get('set-cookie')).toBe('employee_session=token-123; Path=/; HttpOnly; Secure; SameSite=Lax')
  })

  it('falls back to the public API origin when the internal API origin is unavailable', async () => {
    process.env.API_INTERNAL_URL = 'http://api:4000/api/v1'
    process.env.API_URL = 'https://api.rentaldrivego.ma'
    const fetchMock = vi.fn()
      .mockRejectedValueOnce(new Error('getaddrinfo ENOTFOUND api'))
      .mockResolvedValueOnce(new Response(JSON.stringify({ error: 'unauthenticated' }), {
        status: 401,
        headers: { 'content-type': 'application/json' },
      }))
    Object.defineProperty(globalThis, 'fetch', { configurable: true, value: fetchMock })

    const { GET } = await import('./route')
    const response = await GET(
      new Request('https://rentaldrivego.ma/dashboard/api/v1/auth/employee/me'),
      { params: { path: ['auth', 'employee', 'me'] } },
    )

    expect(fetchMock).toHaveBeenNthCalledWith(1, new URL('http://api:4000/api/v1/auth/employee/me'), expect.any(Object))
    expect(fetchMock).toHaveBeenNthCalledWith(2, new URL('https://api.rentaldrivego.ma/api/v1/auth/employee/me'), expect.any(Object))
    expect(response.status).toBe(401)
    await expect(response.json()).resolves.toEqual({ error: 'unauthenticated' })
  })
})
