import "server-only";

import { headers } from "next/headers";

type HeaderSource = Pick<Headers, "get">;

/** Best-effort client IP. Behind Vercel or a reverse proxy the first forwarded address is the client. */
export function clientIp(source: HeaderSource) {
  const forwarded = source.get("x-forwarded-for")?.split(",")[0]?.trim();
  return forwarded || source.get("x-real-ip") || "unknown";
}

export async function requestClientIp() {
  return clientIp(await headers());
}

/**
 * CSRF guard for Route Handlers that change state. Server Actions get this
 * check from Next.js; Route Handlers do not. Browsers send `Origin` on every
 * cross-origin POST, so a mismatch means the request came from another site.
 *
 * `Sec-Fetch-Site` is set by the browser and can't be changed by page scripts
 * or rewritten by a proxy, so it decides when present. Comparing `Origin` with
 * the host headers is the fallback for older browsers; it accepts either the
 * proxy's `X-Forwarded-Host` or `Host`, since proxies set them differently.
 */
export function isSameOrigin(request: Request) {
  const fetchSite = request.headers.get("sec-fetch-site");
  if (fetchSite) return fetchSite === "same-origin";

  const origin = request.headers.get("origin");
  if (!origin) return false;
  let originHost: string;
  try {
    originHost = new URL(origin).host;
  } catch {
    return false;
  }
  const hosts = [
    ...(request.headers.get("x-forwarded-host")?.split(",") ?? []),
    request.headers.get("host") ?? "",
  ].map((host) => host.trim().toLowerCase());
  return hosts.includes(originHost.toLowerCase());
}
