import { cookies, headers } from "next/headers"
import { redirect } from "next/navigation"

import { getCookieCache } from "better-auth/cookies"

import { env } from "@/lib/env"
import { isAdmin, isStaff } from "@/lib/authz"

type ServerSession = Awaited<ReturnType<typeof getCookieCache>>

async function serializeCookies() {
  const store = await cookies()
  return store.getAll().map((cookie) => `${cookie.name}=${cookie.value}`).join("; ")
}

async function buildRequest() {
  const cookieHeader = await serializeCookies()
  const headerList = await headers()
  const userAgent = headerList.get("user-agent") ?? ""
  const ip =
    headerList.get("x-forwarded-for") ||
    headerList.get("x-real-ip") ||
    headerList.get("cf-connecting-ip") ||
    headerList.get("x-client-ip") ||
    undefined

  return new Request(env.BETTER_AUTH_URL ?? "http://localhost:3000", {
    headers: {
      cookie: cookieHeader,
      "user-agent": userAgent,
      ...(ip ? { "x-forwarded-for": ip } : {}),
    },
  })
}

export async function getServerSession(): Promise<ServerSession | null> {
  try {
    const request = await buildRequest()
    const session = await getCookieCache(request)
    return session ?? null
  } catch (error) {
    console.error("Failed to read Better Auth session", error)
    return null
  }
}

export async function assertAuthenticatedSession() {
  const session = await getServerSession()
  return session?.user ? session : null
}

export async function requireAuthenticatedSession() {
  const session = await assertAuthenticatedSession()
  if (!session) {
    redirect("/login")
  }
  return session
}

export async function assertStaffSession() {
  const session = await assertAuthenticatedSession()
  if (!session) return null
  if (!isStaff(session.user.role)) {
    return null
  }
  return session
}

export async function requireStaffSession() {
  const session = await assertStaffSession()
  if (!session) {
    redirect("/portal")
  }
  return session
}

export async function assertAdminSession() {
  const session = await assertAuthenticatedSession()
  if (!session) return null
  if (!isAdmin(session.user.role)) {
    return null
  }
  return session
}

export async function requireAdminSession() {
  const session = await assertAdminSession()
  if (!session) {
    redirect("/dashboard")
  }
  return session
}
