import { cookies } from "next/headers"
import { NextResponse } from "next/server"
import {
  resolveServerOidcConfig,
  getAppOrigin,
  oidcServerFetchHeaders,
} from "@/lib/auth/oidc-config"
import { platformUserFromToken } from "@/lib/auth/jwt-claims"
import {
  applySessionCookies,
  type TokenResponse,
} from "@/lib/auth/session"

const PKCE_COOKIE = "ulti_pkce_verifier"
const STATE_COOKIE = "ulti_oauth_state"
const INTENT_COOKIE = "ulti_auth_intent"
const PREVIOUS_SUB_COOKIE = "ulti_auth_previous_sub"

export async function GET(request: Request) {
  const url = new URL(request.url)
  const appOrigin = getAppOrigin()
  const code = url.searchParams.get("code")
  const state = url.searchParams.get("state")
  const oauthError = url.searchParams.get("error")

  if (oauthError) {
    const desc = url.searchParams.get("error_description") ?? oauthError
    return NextResponse.redirect(
      new URL(`/login?error=${encodeURIComponent(desc)}`, appOrigin)
    )
  }

  if (!code || !state) {
    return NextResponse.redirect(
      new URL("/login?error=missing_code", appOrigin)
    )
  }

  const jar = await cookies()
  const expectedState = jar.get(STATE_COOKIE)?.value
  const verifier = jar.get(PKCE_COOKIE)?.value
  const returnTo = jar.get("ulti_auth_return")?.value ?? "/mail/inbox"
  const authIntent = jar.get(INTENT_COOKIE)?.value
  const previousSub = jar.get(PREVIOUS_SUB_COOKIE)?.value

  if (!expectedState || state !== expectedState || !verifier) {
    return NextResponse.redirect(
      new URL(
        `/login?error=${encodeURIComponent(
          !expectedState || !verifier
            ? "invalid_state:missing_oauth_cookies"
            : "invalid_state:state_mismatch"
        )}`,
        appOrigin
      )
    )
  }

  let cfg
  try {
    cfg = await resolveServerOidcConfig()
  } catch (err) {
    const message =
      err instanceof Error ? err.message : "oidc_discovery_failed"
    return NextResponse.redirect(
      new URL(`/login?error=${encodeURIComponent(message)}`, appOrigin)
    )
  }
  const body = new URLSearchParams({
    grant_type: "authorization_code",
    client_id: cfg.clientId,
    client_secret: cfg.clientSecret,
    code,
    redirect_uri: cfg.redirectUri,
    code_verifier: verifier,
  })

  let tokens: TokenResponse
  try {
    const res = await fetch(cfg.tokenEndpoint, {
      method: "POST",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        ...oidcServerFetchHeaders(),
      },
      body,
    })
    if (!res.ok) {
      const text = await res.text()
      return NextResponse.redirect(
        new URL(
          `/login?error=${encodeURIComponent(`token_exchange_failed:${text.slice(0, 120)}`)}`,
          appOrigin
        )
      )
    }
    tokens = (await res.json()) as TokenResponse
  } catch (err) {
    const message = err instanceof Error ? err.message : "token_exchange_failed"
    return NextResponse.redirect(
      new URL(`/login?error=${encodeURIComponent(message)}`, appOrigin)
    )
  }

  if (!tokens.id_token) {
    return NextResponse.redirect(
      new URL("/login?error=no_id_token", appOrigin)
    )
  }

  const bearer = tokens.id_token

  const newUser = platformUserFromToken(bearer)
  const completeUrl = new URL("/auth/complete", appOrigin)
  completeUrl.searchParams.set("returnTo", returnTo)
  if (
    authIntent === "add_account" &&
    previousSub &&
    newUser?.sub === previousSub
  ) {
    completeUrl.searchParams.set("accountNotice", "same")
  }

  const response = NextResponse.redirect(completeUrl)

  response.cookies.delete(PKCE_COOKIE)
  response.cookies.delete(STATE_COOKIE)
  response.cookies.delete("ulti_auth_return")
  response.cookies.delete(INTENT_COOKIE)
  response.cookies.delete(PREVIOUS_SUB_COOKIE)

  applySessionCookies(response, tokens, bearer)

  return response
}
