/**
 * GET /api/admin/users — paginated list with search + filter.
 *
 * Query params:
 *   q       — search substring (name/email, case-insensitive)
 *   role    — filter by org role: owner | admin | editor | viewer
 *   status  — active | suspended
 *   page    — 1-indexed
 *   limit   — default 50, max 200
 *
 * Superadmin-only (enforced by middleware + requireSuperadmin).
 */

import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { requireSuperadmin, withAdminTiming } from "@/lib/admin-auth";
import type { Prisma } from "@prisma/client";

export const dynamic = "force-dynamic";

export async function GET(req: Request) {
  const denied = await requireSuperadmin();
  if (denied) return denied;

  const { searchParams } = new URL(req.url);
  const q = (searchParams.get("q") ?? "").trim();
  const roleFilter = searchParams.get("role") ?? "";
  const page = Math.max(1, Number(searchParams.get("page") ?? 1));
  const limit = Math.max(1, Math.min(200, Number(searchParams.get("limit") ?? 50)));
  const skip = (page - 1) * limit;

  return NextResponse.json(await withAdminTiming("users.list", async () => {
    // Build WHERE clause. Search matches name OR email; role filter
    // joins via OrgMembership so we can include/exclude by actual
    // platform role rather than a surrogate flag.
    const where: Prisma.UserWhereInput = {};
    if (q) {
      where.OR = [
        { email: { contains: q, mode: "insensitive" } },
        { name: { contains: q, mode: "insensitive" } },
      ];
    }
    if (roleFilter) {
      where.memberships = { some: { role: roleFilter } };
    }

    const [users, total] = await Promise.all([
      prisma.user.findMany({
        where,
        orderBy: { createdAt: "desc" },
        skip,
        take: limit,
        include: {
          memberships: {
            select: { role: true, orgId: true, organization: { select: { name: true } } },
          },
          _count: { select: { memberships: true } },
        },
      }),
      prisma.user.count({ where }),
    ]);

    // Secondary lookup: how many brands each user has access to
    // (through their org memberships). One groupBy aggregation per
    // page-sized batch keeps this O(pageSize) rather than N+1.
    const orgIds = Array.from(new Set(users.flatMap((u) => u.memberships.map((m) => m.orgId))));
    const brandCounts = orgIds.length > 0
      ? await prisma.brand.groupBy({
          by: ["orgId"],
          where: { orgId: { in: orgIds } },
          _count: true,
        })
      : [];
    const brandCountByOrg = new Map(brandCounts.map((b) => [b.orgId, b._count]));

    return {
      users: users.map((u) => ({
        id: u.id,
        email: u.email,
        name: u.name,
        image: u.image,
        createdAt: u.createdAt.toISOString(),
        roles: u.memberships.map((m) => ({ role: m.role, orgName: m.organization.name })),
        primaryRole: u.memberships[0]?.role ?? null,
        brandCount: u.memberships.reduce((sum, m) => sum + (brandCountByOrg.get(m.orgId) ?? 0), 0),
        // Placeholder until an isSuspended column exists; sign-ups
        // from Clerk flow through OrgMembership so we can infer
        // activity from there.
        status: "active" as const,
      })),
      total,
      page,
      limit,
      hasMore: skip + users.length < total,
    };
  }));
}
