/**
 * GET /api/admin/users/[userId] — full user detail for the admin
 * detail drawer. Returns:
 *   - base User row (id / email / name / image / createdAt)
 *   - all org memberships with org name + role
 *   - brands they have access to (via memberships → Brand)
 *   - recent PlatformEvent activity (last 30, newest first)
 *   - integration connection stats (count of connected BrandIntegrations
 *     across their brands)
 *
 * Superadmin-only.
 */

import { NextResponse } from "next/server";
import { clerkClient } from "@clerk/nextjs/server";
import { prisma } from "@/lib/prisma";
import { getSuperadmin, requireSuperadmin, withAdminTiming } from "@/lib/admin-auth";

export const dynamic = "force-dynamic";

/**
 * DELETE /api/admin/users/[userId] — destructive removal.
 * Wipes Clerk + cascades the User row through Prisma. The
 * OrgMembership / BrandMembership / PlatformEvent rows tied to the
 * user cascade via the schema's onDelete: Cascade. Logged to
 * ComplianceEvent under "user_deleted".
 *
 * Cannot delete the requesting admin's own account — returns 400.
 *
 * Superadmin-only.
 */
export async function DELETE(_req: Request, ctx: { params: { userId: string } }) {
  const denied = await requireSuperadmin();
  if (denied) return denied;
  const admin = await getSuperadmin();
  if (!admin) return NextResponse.json({ error: "Forbidden" }, { status: 403 });

  const { userId } = ctx.params;
  if (!userId) return NextResponse.json({ error: "userId required" }, { status: 400 });
  if (userId === admin.userId) {
    return NextResponse.json({ error: "Cannot delete your own account" }, { status: 400 });
  }

  return NextResponse.json(await withAdminTiming("users.delete", async () => {
    // Capture identifying info before we cascade so the audit row
    // carries the email rather than just the opaque userId.
    const user = await prisma.user.findUnique({
      where: { id: userId },
      select: { email: true },
    });

    // Clerk first — if Clerk fails the user remains in our DB and
    // can be retried; deleting our row first would leave a Clerk
    // ghost. Clerk failure is non-fatal (best-effort) so users
    // already removed from Clerk can still be cleaned out of our
    // DB.
    let clerkOk = true;
    try {
      const clerk = await clerkClient();
      await clerk.users.deleteUser(userId);
    } catch {
      clerkOk = false;
    }

    await prisma.user.delete({ where: { id: userId } }).catch(() => {});

    await prisma.complianceEvent.create({
      data: {
        action: "user_deleted",
        identifier: user?.email ?? userId,
        details: { userId, clerkOk } as object,
        requestedBy: admin.userId,
      },
    }).catch(() => {});

    return { ok: true as const, clerkOk };
  }));
}

export async function GET(_req: Request, ctx: { params: { userId: string } }) {
  const denied = await requireSuperadmin();
  if (denied) return denied;

  const { userId } = ctx.params;
  if (!userId) return NextResponse.json({ error: "userId required" }, { status: 400 });

  return NextResponse.json(await withAdminTiming("users.detail", async () => {
    const user = await prisma.user.findUnique({
      where: { id: userId },
      include: {
        memberships: {
          include: {
            organization: {
              include: {
                brands: {
                  select: { id: true, name: true, domain: true, createdAt: true },
                  orderBy: { createdAt: "desc" },
                },
              },
            },
          },
        },
      },
    });
    if (!user) return { error: "not_found" as const };

    const brandIds = user.memberships.flatMap((m) => m.organization.brands.map((b) => b.id));
    const [activity, integrationStats, brandGrants] = await Promise.all([
      prisma.platformEvent.findMany({
        where: { userId },
        orderBy: { timestamp: "desc" },
        take: 30,
        select: { id: true, action: true, category: true, metadata: true, brandId: true, timestamp: true },
      }),
      brandIds.length > 0
        ? prisma.brandIntegration.groupBy({
            by: ["integrationId", "connected"],
            where: { brandId: { in: brandIds } },
            _count: true,
          })
        : Promise.resolve([]),
      // Explicit BrandMembership rows — distinct from "implicit via
      // org owner/admin" so the detail panel can show which grants
      // are revocable from the per-brand list.
      prisma.brandMembership.findMany({
        where: { userId },
        select: { brandId: true, role: true, brand: { select: { id: true, name: true, domain: true } } },
      }),
    ]);

    // Reshape integrationStats into { ga4: { connected: n, total: m }, ... }.
    const integrationMap = new Map<string, { connected: number; total: number }>();
    for (const row of integrationStats as Array<{ integrationId: string; connected: boolean; _count: number }>) {
      const entry = integrationMap.get(row.integrationId) ?? { connected: 0, total: 0 };
      entry.total += row._count;
      if (row.connected) entry.connected += row._count;
      integrationMap.set(row.integrationId, entry);
    }

    return {
      user: {
        id: user.id,
        email: user.email,
        name: user.name,
        image: user.image,
        createdAt: user.createdAt.toISOString(),
        updatedAt: user.updatedAt.toISOString(),
      },
      memberships: user.memberships.map((m) => ({
        orgId: m.orgId,
        orgName: m.organization.name,
        role: m.role,
        brands: m.organization.brands,
      })),
      brandCount: brandIds.length,
      // Per-brand explicit grants — what the admin's "Brands" panel
      // renders + what the Revoke button targets. brandRole is the
      // BrandMembership.role (may differ from the org-level role).
      brandGrants: brandGrants.map((g) => ({
        brandId: g.brandId,
        brandName: g.brand.name,
        brandDomain: g.brand.domain,
        brandRole: g.role,
      })),
      activity: activity.map((a) => ({ ...a, timestamp: a.timestamp.toISOString() })),
      integrations: Array.from(integrationMap.entries()).map(([id, v]) => ({
        integrationId: id,
        connected: v.connected,
        total: v.total,
      })),
    };
  }));
}
