/**
 * Server-side plan enforcement for API routes.
 * ─────────────────────────────────────────────
 * Usage:
 *
 *   const denied = await requirePlanFeature(brandId, "rank_tracker");
 *   if (denied) return denied;
 *
 * Returns null when allowed, or a NextResponse with the canonical
 * upgrade_required envelope when the brand's plan doesn't include
 * the feature:
 *
 *   {
 *     error: "upgrade_required",
 *     feature: "rank_tracker",
 *     currentPlan: "growth",
 *     requiredPlan: "professional"
 *   }
 *
 * The client auto-opens the upgrade modal on this shape (see
 * src/lib/api-client.ts fetch wrapper in a subsequent commit).
 */

import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { getSuperadmin } from "@/lib/admin-auth";
import {
  planHasFeature,
  recommendPlanFor,
  resolveEffectivePlan,
  type FeatureKey,
  type PlanId,
} from "@/lib/plan-config";

export interface PlanGuardBrand {
  plan: PlanId;
  planExpiresAt: Date | null;
}

/** Fetch the plan context for a brand. Returns null when the brand
 *  id is unknown (callers should 404). */
export async function getBrandPlan(brandId: string): Promise<PlanGuardBrand | null> {
  const brand = await prisma.brand.findUnique({
    where: { id: brandId },
    select: { plan: true, planExpiresAt: true },
  });
  if (!brand) return null;
  return {
    plan: (brand.plan as PlanId) ?? "trial",
    planExpiresAt: brand.planExpiresAt ?? null,
  };
}

/** Enforce that the brand's plan includes the given feature.
 *  Returns null when allowed, or a 403 Response when not.
 *
 *  Superadmin bypass: if the calling user is a platform superadmin
 *  (Clerk publicMetadata.role === "superadmin"), the function
 *  returns null unconditionally. Owners of the platform must never
 *  hit upgrade_required errors when probing customer features.
 */
export async function requirePlanFeature(
  brandId: string,
  feature: FeatureKey,
): Promise<Response | null> {
  // Superadmin check FIRST — cheap (one Clerk session read), fail-
  // open-for-superadmins. Done before the brand lookup so even a
  // bad brandId from a superadmin path returns 404 with consistent
  // semantics rather than a misleading upgrade_required.
  if (await getSuperadmin()) return null;

  const ctx = await getBrandPlan(brandId);
  if (!ctx) {
    return NextResponse.json({ error: "Brand not found" }, { status: 404 });
  }
  if (planHasFeature(ctx, feature)) return null;

  const current = resolveEffectivePlan(ctx);
  const required = recommendPlanFor(feature);
  return NextResponse.json(
    {
      error: "upgrade_required",
      message: `Your plan doesn't include ${feature}. Upgrade to ${required ?? "a higher plan"} to unlock it.`,
      feature,
      currentPlan: current,
      requiredPlan: required,
    },
    { status: 403 },
  );
}

/** Brand-limit check for the "Add Brand" flow. Returns null when
 *  allowed, or a 403 when the user is at their plan's maxBrands.
 *  Pass the orgId so we count brands in the same organization.
 *  Superadmins bypass the cap (same rationale as requirePlanFeature). */
export async function requireBrandSlotAvailable(
  orgId: string,
  plan: PlanId,
  planExpiresAt: Date | null = null,
): Promise<Response | null> {
  if (await getSuperadmin()) return null;

  // Unlimited plans are never blocked.
  const { PLANS } = await import("@/lib/plan-config");
  const effective = resolveEffectivePlan({ plan, planExpiresAt });
  const limit = PLANS[effective].limits.maxBrands;
  if (limit === "unlimited") return null;

  const used = await prisma.brand.count({ where: { orgId } });
  if (used < limit) return null;

  const required = nextPlanUp(effective);
  return NextResponse.json(
    {
      error: "upgrade_required",
      reason: "brand_limit",
      message: `You're using ${used} of ${limit} brands on ${effective}. Upgrade to ${required ?? "Enterprise"} for more.`,
      currentPlan: effective,
      requiredPlan: required,
      limit: { used, max: limit },
    },
    { status: 403 },
  );
}

function nextPlanUp(plan: PlanId): PlanId | null {
  const order: PlanId[] = ["growth", "professional", "agency", "agency_pro", "enterprise"];
  const i = order.indexOf(plan);
  return i >= 0 && i < order.length - 1 ? order[i + 1] : null;
}
