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

const nextServer = vi.hoisted(() => {
  const next = vi.fn((init?: { request?: { headers?: Headers } }) => ({
    kind: 'next',
    init,
    cookies: {
      set: vi.fn(),
    },
  }))
  const redirect = vi.fn((url: URL, status?: number) => ({
    kind: 'redirect',
    url: url.toString(),
    status,
  }))
  const MockNextResponse = vi.fn((body?: string, init?: { status?: number }) => ({
    kind: 'response',
    body,
    status: init?.status,
  })) as any
  MockNextResponse.next = next
  MockNextResponse.redirect = redirect
  return { next, redirect, MockNextResponse }
})

vi.mock('next/server', () => ({
  NextResponse: nextServer.MockNextResponse,
}))

function request(options: { cookies?: Record<string, string>; headers?: Record<string, string> } = {}) {
  const cookies = new Map(Object.entries(options.cookies ?? {}))
  const headers = new Headers(options.headers ?? {})
  return {
    nextUrl: cloneableUrl('http://localhost:3000/'),
    cookies: {
      get: vi.fn((name: string) => {
        const value = cookies.get(name)
        return value ? { value } : undefined
      }),
    },
    headers,
  }
}

function cloneableUrl(input: string): URL {
  const url = new URL(input)
  ;(url as URL & { clone: () => URL }).clone = () => cloneableUrl(url.toString())
  return url
}

function middlewareRequest(input: string) {
  return {
    cookies: {
      get: vi.fn(),
    },
    headers: new Headers(),
    nextUrl: cloneableUrl(input),
  }
}

beforeEach(() => {
  nextServer.next.mockClear()
  nextServer.redirect.mockClear()
})

describe('storefront proxy language bootstrap', () => {

  it('rejects proxy subrequest headers before language handling', async () => {
    const { proxy } = await import('./proxy')

    const response = proxy(request({
      headers: { 'x-middleware-subrequest': 'middleware:middleware' },
    }) as never) as any

    expect(response).toEqual({ kind: 'response', body: 'Unsupported internal request header', status: 400 })
    expect(nextServer.next).not.toHaveBeenCalled()
  })
  it('does nothing when the canonical shared language cookie is valid', async () => {
    const { proxy } = await import('./proxy')

    const response = proxy(request({ cookies: { 'rentaldrivego-language': 'fr' } }) as never) as any

    expect(response.kind).toBe('next')
    expect(nextServer.next).toHaveBeenCalledWith()
    expect(response.cookies.set).not.toHaveBeenCalled()
  })

  it('migrates the legacy storefront language cookie into the shared cookie and request headers', async () => {
    const { proxy } = await import('./proxy')

    const response = proxy(request({
      cookies: { 'storefront-language': 'ar' },
      headers: { cookie: 'session=abc' },
    }) as never) as any

    expect(response.cookies.set).toHaveBeenCalledWith('rentaldrivego-language', 'ar', expect.objectContaining({
      path: '/',
      sameSite: 'lax',
    }))
    expect(response.init?.request?.headers?.get('cookie')).toBe('session=abc; rentaldrivego-language=ar')
  })

  it('detects Arabic and French from Accept-Language before falling back to English', async () => {
    const { proxy } = await import('./proxy')

    const arabic = proxy(request({ headers: { 'accept-language': 'ar-MA,fr;q=0.8,en;q=0.6' } }) as never) as any
    expect(arabic.cookies.set).toHaveBeenCalledWith('rentaldrivego-language', 'ar', expect.any(Object))
    expect(arabic.init?.request?.headers?.get('cookie')).toBe('rentaldrivego-language=ar')

    const french = proxy(request({ headers: { 'accept-language': 'de-DE,fr-FR;q=0.7,en;q=0.3' } }) as never) as any
    expect(french.cookies.set).toHaveBeenCalledWith('rentaldrivego-language', 'fr', expect.any(Object))

    const fallback = proxy(request({ headers: { 'accept-language': 'de-DE,es;q=0.9' } }) as never) as any
    expect(fallback.cookies.set).toHaveBeenCalledWith('rentaldrivego-language', 'en', expect.any(Object))
  })

  it('rejects invalid shared and legacy language values before resolving from headers', async () => {
    const { proxy } = await import('./proxy')

    const response = proxy(request({
      cookies: { 'rentaldrivego-language': 'es', 'storefront-language': 'it' },
      headers: { 'accept-language': 'fr-CA,ar;q=0.5' },
    }) as never) as any

    expect(response.cookies.set).toHaveBeenCalledWith('rentaldrivego-language', 'fr', expect.any(Object))
    expect(response.init?.request?.headers?.get('cookie')).toBe('rentaldrivego-language=fr')
  })
})

describe('storefront middleware dashboard path canonicalization', () => {
  it('redirects duplicate dashboard prefixes to the clean dashboard URL', async () => {
    const { proxy } = await import('./proxy')

    const response = proxy(middlewareRequest('http://localhost:3000/dashboard/dashboard') as never)

    expect(response).toEqual({ kind: 'redirect', url: 'http://localhost:3000/dashboard', status: 307 })
  })

  it('preserves nested dashboard paths while removing the duplicate prefix', async () => {
    const { proxy } = await import('./proxy')

    const response = proxy(middlewareRequest('http://localhost:3000/dashboard/dashboard/fleet?tab=active') as never)

    expect(response).toEqual({ kind: 'redirect', url: 'http://localhost:3000/dashboard/fleet?tab=active', status: 307 })
  })
})
