/**
 * Shared rollup computation for SiteTagDailyRollup.
 *
 * Used by both the hourly cron (GET /api/cron/site-tag-rollup) and the
 * admin backfill endpoint (POST /api/admin/backfill-site-tag-rollup) so
 * the two paths cannot drift. Any change to rollup logic belongs here.
 *
 * All eight queries are bounded to a single UTC day and hit the
 * (trackedSiteId, eventType, timestamp) index, so they are fast even for
 * high-volume brands with 300K+ events/day.
 */

import { prisma } from "@/lib/prisma";
import { extractPath, canonicalType } from "@/lib/services/site-tag-analytics";
import { EXCLUDED_CONVERSION_TYPES, countedConversionWhere } from "@/lib/conversions/counted-where";
import { CONVERSION_TIERS } from "@/lib/conversions/tiers";

export async function computeOneDayRollup(
  siteId: string,
  brandId: string,
  date: Date,
  requireSuccessConfirmed = false,
): Promise<void> {
  const dayEnd = new Date(date.getTime() + 86_400_000);

  // All eight queries run in parallel, each bounded to [date, dayEnd).
  // conversions uses the SAME isDuplicateOf / invalidatedReason filter as
  // conversionsByType so the headline count is consistent with the breakdown.
  const [
    pageViewCount,
    sessionCount,
    topPagesGroup,
    topReferrersGroup,
    conversionCount,
    conversionTypeGroup,
    eventTypeGroup,
    outboundClickCount,
  ] = await Promise.all([
    prisma.trackedEvent.count({
      where: { trackedSiteId: siteId, eventType: "page_view", timestamp: { gte: date, lt: dayEnd } },
    }),
    prisma.trackedEvent.count({
      where: { trackedSiteId: siteId, eventType: "session_start", timestamp: { gte: date, lt: dayEnd } },
    }),
    prisma.trackedEvent.groupBy({
      by: ["pageUrl"],
      where: { trackedSiteId: siteId, eventType: "page_view", timestamp: { gte: date, lt: dayEnd } },
      _count: { pageUrl: true },
      orderBy: { _count: { pageUrl: "desc" } },
      take: 50,
    }),
    prisma.trackedEvent.groupBy({
      by: ["referrer"],
      where: { trackedSiteId: siteId, eventType: "page_view", timestamp: { gte: date, lt: dayEnd } },
      _count: { referrer: true },
      orderBy: { _count: { referrer: "desc" } },
      take: 25,
    }),
    prisma.siteConversion.count({
      where: {
        ...countedConversionWhere(brandId, { requireSuccessConfirmed }),
        timestamp: { gte: date, lt: dayEnd },
      },
    }),
    prisma.siteConversion.groupBy({
      by: ["conversionType"],
      where: {
        ...countedConversionWhere(brandId, { requireSuccessConfirmed }),
        timestamp: { gte: date, lt: dayEnd },
      },
      _count: true,
    }),
    prisma.trackedEvent.groupBy({
      by: ["eventType"],
      where: { trackedSiteId: siteId, timestamp: { gte: date, lt: dayEnd } },
      _count: true,
    }),
    prisma.siteEvent.count({
      where: { brandId, eventType: "outbound_click", timestamp: { gte: date, lt: dayEnd } },
    }),
  ]);

  // Collapse page URLs to paths
  const pagePathCounts = new Map<string, number>();
  for (const row of topPagesGroup) {
    const path = extractPath(row.pageUrl);
    pagePathCounts.set(path, (pagePathCounts.get(path) ?? 0) + row._count.pageUrl);
  }
  const topPages = Array.from(pagePathCounts.entries())
    .sort(([, a], [, b]) => b - a)
    .slice(0, 10)
    .map(([url, views]) => ({ url, views }));

  // Collapse referrers to domains
  const refDomainCounts = new Map<string, number>();
  for (const row of topReferrersGroup) {
    const source = row.referrer
      ? (() => {
          try { return new URL(row.referrer).hostname.replace(/^www\./, ""); }
          catch { return row.referrer; }
        })()
      : "(direct)";
    refDomainCounts.set(source, (refDomainCounts.get(source) ?? 0) + row._count.referrer);
  }
  const byReferrer = Array.from(refDomainCounts.entries())
    .sort(([, a], [, b]) => b - a)
    .slice(0, 10)
    .map(([source, views]) => ({ source, views }));

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

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

  await prisma.siteTagDailyRollup.upsert({
    where: { brandId_date: { brandId, date } },
    update: {
      pageViews: pageViewCount,
      sessions: sessionCount,
      conversions: conversionCount,
      topPages,
      byReferrer,
      conversionsByType,
      conversionsByTier,
      eventCountsByType,
      outboundClickCount,
    },
    create: {
      brandId,
      date,
      pageViews: pageViewCount,
      sessions: sessionCount,
      conversions: conversionCount,
      topPages,
      byReferrer,
      conversionsByType,
      conversionsByTier,
      eventCountsByType,
      outboundClickCount,
    },
  });
}
