/**
 * Pure subdomain routing decisions for the Edge middleware.
 *
 * Kept dependency-free from Next.js so the exact host/pathmap contract can be
 * unit-tested without an Edge runtime (see tests/e2e/subdomain_routing.test.ts).
 * The middleware (src/middleware.ts) interprets the decision and applies the
 * CSRF cookie + anonymous-admin responses around it.
 */

import { hostIsSiteFirstParty } from "@/lib/seo/site";

/**
 * Content that exists only on the main host. The `app.*` subdomain is the
 * dashboard only, so each of these prefixes is redirected to the bare domain
 * (e.g. `app.<domain>/auth/login` → `<domain>/auth/login`).
 */
export const MAIN_HOST_ONLY_PREFIXES = [
  "/auth",
  "/admin",
  "/terms",
  "/privacy",
  "/disclaimer",
];

/**
 * Boundary-aware admin path detection: /admin and /admin/* are admin, as are
 * /api/admin and /api/admin/*. /administrator or /api/adminx are NOT — a bare
 * prefix match would silently admin-gate any similarly named future route.
 */
export function isAdminPath(pathname: string): boolean {
  return (
    /^\/admin(?:\/|$)/.test(pathname) ||
    /^\/api\/admin(?:\/|$)/.test(pathname)
  );
}

/**
 * Boundary-aware dashboard path detection: /dashboard and /dashboard/* only.
 * /dashboarding is not a dashboard route.
 */
export function isDashboardPath(pathname: string): boolean {
  return /^\/dashboard(?:\/|$)/.test(pathname);
}

export type SubdomainDecision =
  /** Serve as-is on the current host (no rewrite). */
  | { kind: "next" }
  /** Internally rewrite to this internal route-group path. */
  | { kind: "rewrite"; pathname: string }
  /** 307-redirect to the main host, keeping path + query. */
  | { kind: "redirect"; pathname: string }
  /** Not a routed subdomain — no decision from this module. */
  | { kind: "none" };

/**
 * Decide what the middleware should do with `pathname` on `hostname`.
 *
 * `admin.<domain>`: anything already under /admin and everything under
 * /api or /dashboard passes through unchanged (the admin UI calls
 * apiFetch("/api/admin/*") and links back to the dashboard — rewriting those
 * would 404). Everything else is rewritten under /admin.
 *
 * `app.<domain>`: only the dashboard surface and its API. The root serves
 * /dashboard, main-host-only content redirects to the bare domain, dashboard
 * sub-routes and API routes pass through, everything else is treated as a
 * dashboard sub-route.
 */
export function decideSubdomain(
  hostname: string,
  pathname: string
): SubdomainDecision {
  // The exact first-party host check (not just the prefix) keeps an unrelated
  // `admin.evil.example` or a spoofed Host header from being treated as our
  // admin surface.
  if (hostname.startsWith("admin.") && hostIsSiteFirstParty(hostname)) {
    if (pathname.startsWith("/api") || pathname.startsWith("/dashboard")) {
      return { kind: "next" };
    }
    if (pathname.startsWith("/admin")) return { kind: "next" };
    return { kind: "rewrite", pathname: pathname === "/" ? "/admin" : `/admin${pathname}` };
  }

  if (hostname.startsWith("app.") && hostIsSiteFirstParty(hostname)) {
    if (pathname === "/") return { kind: "rewrite", pathname: "/dashboard" };

    const isMainHostOnly = MAIN_HOST_ONLY_PREFIXES.some(
      (prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`)
    );
    if (isMainHostOnly) return { kind: "redirect", pathname };

    if (pathname.startsWith("/dashboard") || pathname.startsWith("/api")) {
      return { kind: "next" };
    }

    return { kind: "rewrite", pathname: `/dashboard${pathname}` };
  }

  return { kind: "none" };
}