import { NextResponse } from 'next/server'

type RouteContext = {
  params: Promise<{ path?: string[] }> | { path?: string[] }
}

const HOP_BY_HOP_HEADERS = new Set([
  'connection',
  'content-encoding',
  'content-length',
  'host',
  'keep-alive',
  'proxy-authenticate',
  'proxy-authorization',
  'set-cookie',
  'te',
  'trailer',
  'transfer-encoding',
  'upgrade',
])

function normalizeApiOrigin(value: string): string {
  return value.replace(/\/+$/, '').replace(/\/api(?:\/v1)?$/, '')
}

function resolveApiOrigins(): string[] {
  return Array.from(new Set([
    process.env.API_INTERNAL_URL,
    process.env.API_URL,
    process.env.NEXT_PUBLIC_API_URL,
    'http://localhost:4000',
  ]
    .filter((value): value is string => Boolean(value))
    .map(normalizeApiOrigin)))
}

function rewriteCookieForDashboard(cookie: string): string {
  return cookie
    .replace(/;\s*Domain=[^;]*/gi, '')
    .replace(/;\s*SameSite=None/gi, '; SameSite=Lax')
}

function getSetCookieHeaders(headers: Headers): string[] {
  const withGetter = headers as Headers & { getSetCookie?: () => string[] }
  if (typeof withGetter.getSetCookie === 'function') return withGetter.getSetCookie()

  const cookie = headers.get('set-cookie')
  return cookie ? [cookie] : []
}

function copyRequestHeaders(request: Request): Headers {
  const headers = new Headers()
  request.headers.forEach((value, key) => {
    if (!HOP_BY_HOP_HEADERS.has(key.toLowerCase())) headers.set(key, value)
  })
  return headers
}

function copyResponseHeaders(upstream: Response): Headers {
  const headers = new Headers()
  upstream.headers.forEach((value, key) => {
    if (!HOP_BY_HOP_HEADERS.has(key.toLowerCase())) headers.set(key, value)
  })
  return headers
}

async function proxyDashboardApi(request: Request, context: RouteContext) {
  const params = await Promise.resolve(context.params)
  const path = (params.path ?? []).map(encodeURIComponent).join('/')
  const requestUrl = new URL(request.url)
  const method = request.method.toUpperCase()
  const hasBody = method !== 'GET' && method !== 'HEAD'
  const body = hasBody ? await request.arrayBuffer() : undefined
  const headers = copyRequestHeaders(request)
  let lastError: unknown = null
  let upstream: Response | null = null

  for (const origin of resolveApiOrigins()) {
    const upstreamUrl = new URL(`/api/v1/${path}${requestUrl.search}`, origin)
    try {
      upstream = await fetch(upstreamUrl, {
        method,
        headers,
        body,
        cache: 'no-store',
      })
      break
    } catch (error) {
      lastError = error
    }
  }

  if (!upstream) {
    const message = lastError instanceof Error ? lastError.message : 'API proxy request failed'
    return NextResponse.json({ error: 'api_proxy_unavailable', message }, { status: 502 })
  }

  const response = new NextResponse(await upstream.arrayBuffer(), {
    status: upstream.status,
    statusText: upstream.statusText,
    headers: copyResponseHeaders(upstream),
  })

  for (const cookie of getSetCookieHeaders(upstream.headers)) {
    response.headers.append('set-cookie', rewriteCookieForDashboard(cookie))
  }

  return response
}

export const runtime = 'nodejs'
export const dynamic = 'force-dynamic'

export async function GET(request: Request, context: RouteContext) {
  return proxyDashboardApi(request, context)
}

export async function POST(request: Request, context: RouteContext) {
  return proxyDashboardApi(request, context)
}

export async function PUT(request: Request, context: RouteContext) {
  return proxyDashboardApi(request, context)
}

export async function PATCH(request: Request, context: RouteContext) {
  return proxyDashboardApi(request, context)
}

export async function DELETE(request: Request, context: RouteContext) {
  return proxyDashboardApi(request, context)
}
