/**
 * Admin Auth Guard
 * ─────────────────
 * Two layers of "admin":
 *   requireAdmin    — legacy email-allowlist check (ADMIN_EMAILS env).
 *                     Used by pre-existing /api/admin-legacy endpoints.
 *   requireSuperadmin — role-based Clerk gate for the new admin portal
 *                     at admin.meseoapp.com. Accepts either:
 *                       • sessionClaims.metadata.role === "superadmin"
 *                       • publicMetadata.role === "superadmin"
 *                       • publicMetadata.isSuperadmin === true
 *                       • email in ADMIN_EMAILS env (belt-and-braces)
 *
 * The middleware at src/middleware.ts enforces the same gate at the
 * edge on admin.meseoapp.com — these helpers are defence-in-depth so
 * API routes stay safe if the hostname routing is ever bypassed.
 */

import { auth } from "@clerk/nextjs/server";
import { NextResponse } from "next/server";
import { getCurrentUser } from "@/lib/auth";

const ADMIN_EMAILS = (process.env.ADMIN_EMAILS || "").split(",").map((e) => e.trim().toLowerCase()).filter(Boolean);

export interface AdminUser { id: string; email: string; name: string | null }

export async function requireAdmin(): Promise<{ ok: true; user: AdminUser } | { ok: false; status: number }> {
  const user = await getCurrentUser();
  if (!user) return { ok: false, status: 401 };

  const email = (user.email || "").toLowerCase();
  if (!email || (ADMIN_EMAILS.length > 0 && !ADMIN_EMAILS.includes(email))) {
    return { ok: false, status: 403 };
  }

  // If no ADMIN_EMAILS configured, deny all (fail-safe)
  if (ADMIN_EMAILS.length === 0) return { ok: false, status: 403 };

  return { ok: true, user: { id: user.id, email, name: user.name ?? null } };
}

// ─── Superadmin (new admin portal) ────────────────────────────────

export interface SuperadminIdentity {
  userId: string;
  email: string | null;
}

/** Boolean check. Returns null when the caller is NOT a superadmin.
 *  Consults Clerk session claims; falls back to ADMIN_EMAILS when
 *  the email is available on the session. */
export async function getSuperadmin(): Promise<SuperadminIdentity | null> {
  const { userId, sessionClaims } = await auth();
  if (!userId) return null;

  const meta = (sessionClaims?.metadata as Record<string, unknown> | undefined) ?? {};
  const publicMeta = (sessionClaims?.publicMetadata as Record<string, unknown> | undefined) ?? {};
  const role = (meta.role as string | undefined) ?? (publicMeta.role as string | undefined);

  const roleSuperadmin = role === "superadmin"
    || meta.isSuperadmin === true
    || publicMeta.isSuperadmin === true;

  const email = (sessionClaims?.email as string | undefined)
    ?? ((sessionClaims as unknown as { email_address?: string } | undefined)?.email_address)
    ?? null;
  const emailSuperadmin = email
    ? ADMIN_EMAILS.length > 0 && ADMIN_EMAILS.includes(email.toLowerCase())
    : false;

  if (!roleSuperadmin && !emailSuperadmin) return null;
  return { userId, email };
}

/** Guard for /api/admin/* routes. Returns null when allowed, or a
 *  NextResponse (401/403) when denied. */
export async function requireSuperadmin(): Promise<Response | null> {
  const { userId } = await auth();
  if (!userId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }
  const admin = await getSuperadmin();
  if (!admin) {
    return NextResponse.json(
      { error: "Forbidden", message: "Superadmin role required." },
      { status: 403 },
    );
  }
  return null;
}

/** Wraps a handler with timing logs so [admin:*] is easy to tail
 *  in Vercel logs. Tags the result row count when detectable. */
export async function withAdminTiming<T>(name: string, handler: () => Promise<T>): Promise<T> {
  const start = Date.now();
  try {
    const result = await handler();
    const elapsed = Date.now() - start;
    const resultCount = Array.isArray(result) ? result.length : undefined;
    console.info(`[admin:${name}] completed`, { elapsed, ...(resultCount != null ? { resultCount } : {}) });
    return result;
  } catch (err) {
    const elapsed = Date.now() - start;
    console.error(`[admin:${name}] failed`, { elapsed, error: err instanceof Error ? err.message : err });
    throw err;
  }
}
