import { NextResponse } from "next/server"
import type { NextRequest } from "next/server"
import { SESSION_COOKIE_NAME } from "@/lib/session-constants"

const LOGIN_PATH = "/login"
const AUTH_VERIFY_PATH = "/api/auth/verify"

/**
 * Subrequest to the same app often fails on some hosts (Passenger, mis-set Host/SSL) or
 * throws; treat failure as "allow through" so the Server Component can run `getSession()`.
 * Otherwise the uncaught error surfaces as 500.
 */
async function sessionIsAllowed(req: NextRequest): Promise<boolean> {
  try {
    const verifyUrl = new URL(AUTH_VERIFY_PATH, req.nextUrl)
    const headers: Record<string, string> = {}
    const cookie = req.headers.get("cookie")
    if (cookie) headers.cookie = cookie
    const auth = req.headers.get("authorization")
    if (auth) headers.authorization = auth

    const res = await fetch(verifyUrl, {
      method: "GET",
      cache: "no-store",
      headers,
    })
    return res.ok
  } catch {
    return true
  }
}

export default async function middleware(req: NextRequest) {
  const { pathname } = req.nextUrl
  const sessionCookie = req.cookies.get(SESSION_COOKIE_NAME)?.value
  const hasCookie = Boolean(sessionCookie?.length)
  const hasBearer = Boolean(
    req.headers.get("authorization")?.toLowerCase().startsWith("bearer "),
  )
  const hasSessionCredential = hasCookie || hasBearer

  if (pathname === "/api/auth/login" || pathname === "/api/auth/logout" || pathname === AUTH_VERIFY_PATH) {
    return NextResponse.next()
  }

  // Public API is protected by bearer service-token at route level.
  if (pathname.startsWith("/api/public/")) {
    return NextResponse.next()
  }

  // /login: allow through; if the cookie is stale, layouts and verify still return 401.
  if (pathname === LOGIN_PATH) {
    return NextResponse.next()
  }

  if (pathname.startsWith("/dashboard")) {
    if (!hasSessionCredential) {
      const loginUrl = new URL(LOGIN_PATH, req.url)
      loginUrl.searchParams.set("callbackUrl", pathname)
      return NextResponse.redirect(loginUrl)
    }
    if (!(await sessionIsAllowed(req))) {
      const loginUrl = new URL(LOGIN_PATH, req.url)
      loginUrl.searchParams.set("callbackUrl", pathname)
      return NextResponse.redirect(loginUrl)
    }
    return NextResponse.next()
  }

  if (pathname.startsWith("/api/admin/")) {
    if (!hasSessionCredential) {
      return NextResponse.json({ error: "Unauthorized" }, { status: 401 })
    }
    if (!(await sessionIsAllowed(req))) {
      return NextResponse.json({ error: "Unauthorized" }, { status: 401 })
    }
    return NextResponse.next()
  }

  // Keep legacy private API routes protected as well.
  if (pathname.startsWith("/api/")) {
    if (!hasSessionCredential) {
      return NextResponse.json({ error: "Unauthorized" }, { status: 401 })
    }
    if (!(await sessionIsAllowed(req))) {
      return NextResponse.json({ error: "Unauthorized" }, { status: 401 })
    }
    return NextResponse.next()
  }

  return NextResponse.next()
}

export const config = {
  matcher: ["/login", "/dashboard/:path*", "/api/:path*"],
}
