/**
 * GET /api/admin/export/user-data
 *
 * Anonymized user list for the data room. NEVER includes PII —
 * userId is hashed (sha256, first 12 chars), no email/name/avatar.
 *
 * Per row: userIdHash, signupDate, brandCount, lastLogin (most
 * recent PlatformEvent), featureAdoptionScore (distinct action
 * keys / total instrumented actions).
 *
 * Always CSV — this is a due-diligence artefact and CSV travels
 * better than JSON across legal review.
 *
 * Superadmin-only.
 */

import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { requireSuperadmin, withAdminTiming } from "@/lib/admin-auth";
import { toCsv } from "@/lib/csv";
import { createHash } from "crypto";

export const dynamic = "force-dynamic";
export const maxDuration = 60;

const HASH_PREFIX_LEN = 12;

// Total catalogue of instrumented action keys we track. Used as the
// denominator for the feature-adoption score — keep in sync with
// PlatformEvent action emissions in src/lib/services/platform-telemetry
// callers. Inflated count is fine; 0% scores would be misleading.
const TOTAL_INSTRUMENTED_ACTIONS = 25;

function hashId(id: string): string {
  return createHash("sha256").update(id).digest("hex").slice(0, HASH_PREFIX_LEN);
}

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

  return withAdminTiming("export.user-data", async () => {
    const users = await prisma.user.findMany({
      include: {
        memberships: { include: { organization: { include: { _count: { select: { brands: true } } } } } },
      },
      orderBy: { createdAt: "asc" },
    });

    const userIds = users.map((u) => u.id);
    // Per-user lastLogin + distinct action count — both as one
    // groupBy each so this stays O(1) extra round-trips.
    const [lastLogins, distinctActions] = await Promise.all([
      userIds.length > 0
        ? prisma.platformEvent.groupBy({
            by: ["userId"],
            where: { userId: { in: userIds } },
            _max: { timestamp: true },
          })
        : Promise.resolve([]),
      userIds.length > 0
        ? prisma.platformEvent.groupBy({
            by: ["userId", "action"],
            where: { userId: { in: userIds } },
            _count: true,
          })
        : Promise.resolve([]),
    ]);

    const lastLoginByUser = new Map<string, Date>();
    for (const r of lastLogins as Array<{ userId: string | null; _max: { timestamp: Date | null } }>) {
      if (r.userId && r._max.timestamp) lastLoginByUser.set(r.userId, r._max.timestamp);
    }
    const distinctActionsByUser = new Map<string, Set<string>>();
    for (const r of distinctActions as Array<{ userId: string | null; action: string }>) {
      if (!r.userId) continue;
      const set = distinctActionsByUser.get(r.userId) ?? new Set<string>();
      set.add(r.action);
      distinctActionsByUser.set(r.userId, set);
    }

    const headers = [
      "userIdHash", "signupDate", "brandCount", "lastLoginDate",
      "featureAdoptionScore", "primaryRole", "orgCount",
    ];
    const rows = users.map((u) => {
      const brandCount = u.memberships.reduce((s, m) => s + m.organization._count.brands, 0);
      const distinct = distinctActionsByUser.get(u.id)?.size ?? 0;
      const adoption = Math.min(100, Math.round((distinct / TOTAL_INSTRUMENTED_ACTIONS) * 100));
      const lastLogin = lastLoginByUser.get(u.id);
      return [
        hashId(u.id),
        u.createdAt.toISOString().slice(0, 10),
        brandCount,
        lastLogin ? lastLogin.toISOString().slice(0, 10) : "",
        adoption,
        u.memberships[0]?.role ?? "",
        u.memberships.length,
      ];
    });

    const csv = toCsv(headers, rows);
    return new NextResponse(csv, {
      status: 200,
      headers: {
        "Content-Type": "text/csv",
        "Content-Disposition": `attachment; filename="users-anonymized-${new Date().toISOString().slice(0, 10)}.csv"`,
      },
    });
  });
}
