/**
 * GET /api/admin/export/platform-metrics?format=json|csv
 *
 * Headline platform metrics for the data room. Pulls the latest
 * PlatformSnapshot if present (so we re-use the cron's heavy
 * aggregations) and falls back to live aggregation when no snapshot
 * exists yet.
 *
 * 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 { NOISE_SITE_EVENT_TYPES } from "@/lib/services/site-event-noise";

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

interface SnapshotMetrics {
  snapshotDate: string;
  totals: Record<string, number>;
  engagement: { dau: number; wau: number; mau: number; stickiness: number };
  last30d: Record<string, number>;
  health: { averageBrandAuditScore: number | null };
}

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

  const format = new URL(req.url).searchParams.get("format") === "csv" ? "csv" : "json";

  return withAdminTiming("export.platform-metrics", async () => {
    const latest = await prisma.platformSnapshot.findFirst({
      orderBy: { snapshotDate: "desc" },
    });

    let metrics: SnapshotMetrics;
    let source: "snapshot" | "live";
    if (latest) {
      metrics = latest.metrics as unknown as SnapshotMetrics;
      source = "snapshot";
    } else {
      // No snapshot yet (cron hasn't run). Compute the headline
      // numbers live so the export still works on day one.
      const [
        users, brands, orgs, events, sessions, siteEvents, conversions,
        gscQueries, gscPages, aiInteractions, siteTagsActive,
      ] = await Promise.all([
        prisma.user.count(),
        prisma.brand.count(),
        prisma.organization.count(),
        prisma.trackedEvent.count(),
        prisma.trackedSession.count(),
        // Exclude third_party_impact + slow_resource (~99% of
        // SiteEvent volume). Keeps the export focused on actual
        // user-behaviour signals and avoids the 30s timeout an
        // unfiltered count hits on production-scale tables.
        prisma.siteEvent.count({
          where: { NOT: { eventType: { in: [...NOISE_SITE_EVENT_TYPES] } } },
        }),
        // intentionally unfiltered: admin-only endpoint; needs raw or all-time counts
        prisma.siteConversion.count(),
        prisma.gscQuery.count(),
        prisma.gscPage.count(),
        prisma.aiInteraction.count(),
        prisma.trackedSite.count({ where: { status: "active" } }),
      ]);
      metrics = {
        snapshotDate: new Date().toISOString(),
        totals: { users, brands, organizations: orgs, events, sessions, siteEvents, conversions, gscQueries, gscPages, aiInteractions, siteTagsActive },
        engagement: { dau: 0, wau: 0, mau: 0, stickiness: 0 },
        last30d: {},
        health: { averageBrandAuditScore: null },
      };
      source = "live";
    }

    const payload = {
      generatedAt: new Date().toISOString(),
      source,
      metrics,
      dictionary: {
        "totals.users": "Distinct platform user accounts",
        "totals.brands": "Brands across all organizations",
        "totals.events": "TrackedEvent rows (Site Tag — page views, clicks, etc.)",
        "totals.sessions": "TrackedSession rows",
        "totals.siteEvents": "SiteEvent rows (signal store + cached AI/seo data)",
        "totals.conversions": "SiteConversion rows",
        "totals.gscQueries": "GSC query-aggregation rows",
        "totals.gscPages": "GSC page-aggregation rows",
        "totals.aiInteractions": "Logged AI calls (with guardrail scoring)",
        "totals.siteTagsActive": "TrackedSite rows with status = active",
        "engagement.dau": "Distinct userIds in PlatformEvent over last 24h",
        "engagement.wau": "Distinct userIds over last 7d",
        "engagement.mau": "Distinct userIds since the start of the snapshot month",
        "engagement.stickiness": "DAU/MAU * 100 (% with 1 decimal). > 25% is excellent for SaaS",
        "health.averageBrandAuditScore": "Average TechnicalAudit.crawlHealth across the latest audit per brand",
      },
    };

    if (format === "csv") {
      const headers = ["metric", "value"];
      const rows: Array<Array<string | number | null>> = [];
      const flatten = (prefix: string, obj: Record<string, unknown>) => {
        for (const [k, v] of Object.entries(obj)) {
          if (v != null && typeof v === "object" && !Array.isArray(v)) {
            flatten(`${prefix}${k}.`, v as Record<string, unknown>);
          } else {
            rows.push([`${prefix}${k}`, v as string | number | null]);
          }
        }
      };
      flatten("", metrics as unknown as Record<string, unknown>);
      const csv = toCsv(headers, rows);
      return new NextResponse(csv, {
        status: 200,
        headers: {
          "Content-Type": "text/csv",
          "Content-Disposition": `attachment; filename="platform-metrics-${new Date().toISOString().slice(0, 10)}.csv"`,
        },
      });
    }

    return NextResponse.json(payload);
  });
}
