/**
 * Auto-Backfill — lightweight SiteConversion gap closer
 * ─────────────────────────────────────────────────────────
 * Called fire-and-forget from getSiteTagAnalytics when the gap
 * between TrackedEvent conversion rows and SiteConversion rows
 * exceeds 2×. Creates missing SiteConversion rows so the numbers
 * converge on the next page load.
 *
 * IMPORTANT: this runs in the BACKGROUND of an analytics request.
 * It must NOT throw, must NOT block the response, and must cap
 * its own runtime so it doesn't exhaust the function's remaining
 * budget. The full /api/admin/debug/backfill-conversions endpoint
 * is the authoritative bulk backfill; this is the lightweight
 * "heal as you go" complement that runs per-brand on every
 * analytics page load.
 */

import { prisma } from "@/lib/prisma";
import { normalizePageUrl } from "@/lib/url-utils";

const CONVERSION_MAP: Record<string, string> = {
  form_submit: "form_submission",
  click_to_call: "phone_call",
  booking_submit: "booking_attempt",
  booking_confirmed: "booking_confirmed",
};

const MAX_EVENTS = 500;
const MAX_RUNTIME_MS = 8_000;
// Match the resolver's FORM_DEDUP_WINDOW_MS so existence checks use
// the same window as real-time dedup.
const DEDUP_WINDOW_MS = 300_000;

export async function backfillConversionsForBrand(
  brandId: string,
  trackedSiteId: string,
): Promise<{ created: number; skipped: number }> {
  const start = Date.now();
  let created = 0;
  let skipped = 0;

  // Resolve cuid → raw session ID mapping
  const sessionRows = await prisma.trackedSession.findMany({
    where: { trackedSiteId },
    select: { id: true, sessionId: true },
    take: 10_000,
  }).catch(() => []);
  const cuidToRaw = new Map(sessionRows.map((s) => [s.id, s.sessionId]));

  for (const [eventType, conversionType] of Object.entries(CONVERSION_MAP)) {
    if (Date.now() - start > MAX_RUNTIME_MS) break;

    const events = await prisma.trackedEvent.findMany({
      where: { trackedSiteId, eventType },
      select: { sessionId: true, pageUrl: true, timestamp: true },
      orderBy: { timestamp: "desc" },
      take: MAX_EVENTS,
    }).catch(() => []);

    for (const ev of events) {
      if (Date.now() - start > MAX_RUNTIME_MS) break;

      const rawSessionId = (ev.sessionId ? cuidToRaw.get(ev.sessionId) : null) ?? ev.sessionId ?? "anon";
      const pageUrl = (ev.pageUrl ?? "").slice(0, 2048);

      try {
        // Dedup: check whether ANY non-auto-backfill SiteConversion row
        // already exists for this brand + type + page within the 5-min
        // window. The session-keyed check used previously only matched rows
        // written by t.source.js (meseo_sid); form-phone.js rows carry
        // _meseo_sid and auto-backfill rows would be a third copy. Querying
        // by normalised pageUrl without a sessionId constraint catches rows
        // from all write paths.
        const windowStart = new Date(ev.timestamp.getTime() - DEDUP_WINDOW_MS);
        const windowEnd   = new Date(ev.timestamp.getTime() + DEDUP_WINDOW_MS);
        const normalizedUrl = normalizePageUrl(pageUrl);
        // intentionally unfiltered: backfill worker; needs undeduped raw events
        const allCandidates = await prisma.siteConversion.findMany({
          where: {
            brandId,
            conversionType,
            formProvider: { not: "auto-backfill" },
            timestamp: { gte: windowStart, lte: windowEnd },
          },
          select: { id: true, pageUrl: true },
        });
        const existing = allCandidates.find((r) => normalizePageUrl(r.pageUrl) === normalizedUrl);
        if (existing) { skipped++; continue; }

        // visitorId from TrackedEvent/TrackedSession is the meseo_sid raw
        // string, not the _meseo_vid localStorage value that both live write
        // paths share. Storing the wrong ID as visitorId breaks the
        // visitorId-keyed dedup. Use "anon" so backfill rows are excluded
        // from visitorId-keyed dedup and backfill-dedup makeWinKey guards.
        await prisma.siteConversion.create({
          data: {
            brandId,
            visitorId: "anon",
            sessionId: rawSessionId,
            conversionType,
            pageUrl,
            formProvider: "auto-backfill",
            formFields: { _source: "auto-backfill", _eventType: eventType } as object,
            detectionMethod: `auto-backfill:${eventType}`,
            timestamp: ev.timestamp,
          },
        });
        created++;
      } catch {
        skipped++;
      }
    }
  }

  if (created > 0) {
    console.info("[auto-backfill] completed", { brandId, created, skipped, elapsed: Date.now() - start });
  }

  return { created, skipped };
}
