import { beforeEach, describe, expect, it, vi } from 'vitest'
import { NextRequest } from 'next/server'
import { ADMIN_WORKSPACES } from '@/lib/domain/modes'
import { sameSiteRedirect } from '@/lib/app-url'

const mocks = vi.hoisted(() => ({
  getSessionUser: vi.fn(),
  readSession: vi.fn(),
  setSessionCookie: vi.fn(),
  logRoleAction: vi.fn(),
  switchContext: vi.fn(),
}))

vi.mock('@/lib/auth', () => ({ getSessionUser: mocks.getSessionUser }))
vi.mock('@/lib/auth/session', () => ({
  readSession: mocks.readSession,
  setSessionCookie: mocks.setSessionCookie,
}))
vi.mock('@/lib/data/modes', () => ({
  logRoleAction: mocks.logRoleAction,
  switchContext: mocks.switchContext,
}))

import { GET as previewMode } from '@/app/api/modes/preview/route'
import { GET as openMode } from '@/app/api/modes/open/route'

beforeEach(() => {
  vi.resetAllMocks()
  mocks.getSessionUser.mockResolvedValue({ id: 'admin-1', name: 'Admin', email: 'admin@example.test', role: 'admin' })
  mocks.readSession.mockResolvedValue({ sub: 'admin-1', role: 'admin' })
  mocks.setSessionCookie.mockResolvedValue(undefined)
  mocks.logRoleAction.mockResolvedValue(undefined)
})

describe('mode navigation behind an internal reverse proxy', () => {
  it('keeps every admin menu destination on the browser site', async () => {
    for (const workspace of ADMIN_WORKSPACES) {
      const req = new NextRequest(`http://localhost:8001/api/modes/preview?workspace=${workspace.key}`)
      const response = await previewMode(req)
      expect(response.status).toBe(307)
      expect(response.headers.get('location')).toBe(workspace.href)
      expect(response.headers.get('location')).not.toContain('localhost')
    }
    expect(mocks.setSessionCookie).toHaveBeenCalledTimes(ADMIN_WORKSPACES.length)
  })

  it('keeps a held-role switch on the browser site', async () => {
    mocks.switchContext.mockResolvedValue({ ok: true, context: { pageContext: 'carrier' } })
    const response = await openMode(new NextRequest('http://localhost:8001/api/modes/open?key=carrier-role'))
    expect(response.status).toBe(307)
    expect(response.headers.get('location')).toBe('/cd-dashboard')
    expect(mocks.setSessionCookie).toHaveBeenCalledWith(expect.objectContaining({ ctx: 'carrier-role', preview: null }))
  })

  it('also keeps authentication and invalid-mode redirects relative', async () => {
    mocks.getSessionUser.mockResolvedValueOnce(null)
    expect((await previewMode(new NextRequest('http://localhost:8001/api/modes/preview?workspace=broker')))
      .headers.get('location')).toBe('/login')
    expect((await previewMode(new NextRequest('http://localhost:8001/api/modes/preview?workspace=invalid')))
      .headers.get('location')).toBe('/admin/moderation')
    mocks.switchContext.mockResolvedValue({ ok: false })
    expect((await openMode(new NextRequest('http://localhost:8001/api/modes/open?key=invalid')))
      .headers.get('location')).toBe('/dashboard')
  })

  it('rejects protocol-relative redirect targets', () => {
    expect(() => sameSiteRedirect('//external.example.test')).toThrow('local path')
  })
})
