/**
 * POST /api/admin/backfill-rollup-v2
 *
 * Backfills conversionsByType, conversionsByTier, eventCountsByType, and
 * outboundClickCount on SiteTagDailyRollup rows created before Phase 19A.25.
 *
 * Idempotent: skips any row where conversionsByType is already populated.
 * Resumable: if interrupted, re-running picks up where it left off.
 *
 * Body: { brandId?: string, days?: number, dryRun?: boolean }
 *   brandId omitted -> process all brands
 *   days defaults to 30
 *   dryRun -> count eligible rows without writing
 */

import { NextResponse } from "next/server";
import { z } from "zod";
import { Prisma } from "@prisma/client";
import { prisma } from "@/lib/prisma";
import { requireSuperadmin } from "@/lib/admin-auth";
import { validateBody } from "@/lib/validation/request";
import { withErrorHandler } from "@/lib/api/with-error-handler";
import { canonicalType } from "@/lib/services/site-tag-analytics";
import { CONVERSION_TIERS } from "@/lib/conversions/tiers";

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

const BodySchema = z.object({
  brandId: z.string().optional(),
  days: z.number().int().min(1).max(90).default(30),
  dryRun: z.boolean().default(false),
});

export const POST = withErrorHandler(async (req: Request) => {
  const authError = await requireSuperadmin();
  if (authError) return authError;

  const body = await validateBody(req, BodySchema);
  if (body instanceof NextResponse) return body;

  const { brandId: targetBrandId, days, dryRun } = body;

  const cutoff = new Date(Date.now() - days * 86_400_000);

  // Find all rollup rows missing the new columns
  const nullRows = await prisma.siteTagDailyRollup.findMany({
    where: {
      ...(targetBrandId ? { brandId: targetBrandId } : {}),
      date: { gte: cutoff },
      conversionsByType: { equals: Prisma.DbNull },
    },
    select: { id: true, brandId: true, date: true },
    orderBy: { date: "asc" },
  });

  if (dryRun) {
    return NextResponse.json({ dryRun: true, eligible: nullRows.length });
  }

  // Resolve brandId -> trackedSiteId mapping (needed for TrackedEvent queries)
  const brandIds = [...new Set(nullRows.map((r) => r.brandId))];
  const sites = await prisma.trackedSite.findMany({
    where: { brandId: { in: brandIds } },
    select: { id: true, brandId: true },
  });
  const siteByBrand = new Map(sites.map((s) => [s.brandId, s.id]));

  let updated = 0;
  let failed = 0;

  for (const row of nullRows) {
    const siteId = siteByBrand.get(row.brandId);
    const date = row.date;
    const dayEnd = new Date(date.getTime() + 86_400_000);

    try {
      const [conversionTypeGroup, eventTypeGroup, outboundClickCount] = await Promise.all([
        // intentionally unfiltered: admin-only endpoint; needs raw or all-time counts
        prisma.siteConversion.groupBy({
          by: ["conversionType"],
          where: {
            brandId: row.brandId,
            timestamp: { gte: date, lt: dayEnd },
            isDuplicateOf: null,
            invalidatedReason: null,
          },
          _count: true,
        }),
        siteId
          ? prisma.trackedEvent.groupBy({
              by: ["eventType"],
              where: { trackedSiteId: siteId, timestamp: { gte: date, lt: dayEnd } },
              _count: true,
            })
          : Promise.resolve([]),
        prisma.siteEvent.count({
          where: {
            brandId: row.brandId,
            eventType: "outbound_click",
            timestamp: { gte: date, lt: dayEnd },
          },
        }),
      ]);

      const conversionsByType: Record<string, number> = {};
      const conversionsByTier: Record<string, number> = { completed: 0, intent: 0, signal: 0 };
      for (const r of conversionTypeGroup) {
        const count = typeof r._count === "number" ? r._count : 0;
        const canonical = canonicalType(r.conversionType);
        conversionsByType[canonical] = (conversionsByType[canonical] ?? 0) + count;
        const tier = CONVERSION_TIERS[r.conversionType] ?? CONVERSION_TIERS[canonical] ?? "completed";
        conversionsByTier[tier] = (conversionsByTier[tier] ?? 0) + count;
      }

      const eventCountsByType: Record<string, number> = {};
      for (const r of eventTypeGroup) {
        const count = typeof r._count === "number" ? r._count : 0;
        eventCountsByType[r.eventType] = count;
      }

      await prisma.siteTagDailyRollup.update({
        where: { id: row.id },
        data: { conversionsByType, conversionsByTier, eventCountsByType, outboundClickCount },
      });

      updated++;
    } catch (err) {
      console.error("[backfill-rollup-v2] row failed", {
        brandId: row.brandId,
        date: row.date.toISOString(),
        err: err instanceof Error ? err.message : err,
      });
      failed++;
    }
  }

  return NextResponse.json({ ok: true, updated, failed, skipped: 0, eligible: nullRows.length });
});
