/**
 * GET /api/debug/verify-form-tracking
 *
 * One-shot end-to-end diagnostic for the Site Tag v2 form / booking
 * tracking pipeline. Runs five independent checks and returns a
 * structured pass/fail report.
 *
 *   1. EVENT ACCEPTANCE       — POST one synthetic event of every
 *      new event type to /api/collect; record status + elapsed.
 *   2. CONVERSION CREATION    — verify SiteConversion side-effect
 *      fired for the conversion-relevant types (form_submit,
 *      booking_submit, booking_confirmed).
 *   3. ANALYTICS AGGREGATION  — query TrackedEvent grouped by
 *      eventType for the synthetic page URL; verify each new type
 *      appears with count >= 1.
 *   4. ADMIN METRIC FIELDS    — fetch /api/admin/platform-metrics
 *      and verify the response shape carries formSubmits, bookings,
 *      formStarts (don't care about counts — schema check only).
 *   5. EVENT LABELS           — verify EVENT_TYPE_LABELS exposes a
 *      humanised label for every new type via eventTypeLabel().
 *
 * Always cleans up the synthetic data it wrote — matches strictly by
 * the test page-URL path AND the per-run _verifyRun timestamp stamp,
 * so it can never delete real events even if a real one happens to
 * land on the same page URL during the run.
 *
 * NOTE on hostname: this route lives at /api/debug/* and works on
 * app.meseoapp.com. On admin.meseoapp.com the middleware rewrites
 * non-passthrough paths to /admin/<path>, so this URL 404s on the
 * admin host. Curl from app.meseoapp.com (or the equivalent main
 * host) to exercise it. Superadmin gate is enforced inside the
 * handler regardless of host.
 *
 * Superadmin-only. Optional ?brandId= param; defaults to the first
 * brand with a TrackedSite.
 */

import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { requireSuperadmin, withAdminTiming } from "@/lib/admin-auth";
import { eventTypeLabel, EVENT_TYPE_LABELS } from "@/lib/services/site-tag-analytics";

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

const TEST_PAGE_PATH = "/debug/verify-form-tracking";

// Every new event type the Site Tag v2 upgrade added. Each gets POSTed
// once to /api/collect during step (1). expectsConversion + expected
// type drive the SiteConversion check in step (2).
const TEST_EVENTS: Array<{
  eventType: string;
  expectsConversion: boolean;
  expectedConversionType?: string;
  metadata: Record<string, unknown>;
}> = [
  { eventType: "form_submit",           expectsConversion: true,  expectedConversionType: "form_submission",   metadata: { source: "native",    form_id: "verify-form" } },
  { eventType: "form_intent",           expectsConversion: false, metadata: { cta_text: "Verify intent" } },
  { eventType: "appointment_intent",    expectsConversion: false, metadata: { cta_text: "Verify schedule" } },
  { eventType: "booking_widget_opened", expectsConversion: false, metadata: { source: "calendly" } },
  { eventType: "booking_step",          expectsConversion: false, metadata: { source: "amelia", step: "2" } },
  { eventType: "booking_submit",        expectsConversion: true,  expectedConversionType: "booking_attempt",   metadata: { source: "amelia" } },
  { eventType: "booking_confirmed",     expectsConversion: true,  expectedConversionType: "booking_confirmed", metadata: { source: "amelia" } },
  { eventType: "plugin_detected",       expectsConversion: false, metadata: { plugin: "Amelia", plugin_key: "amelia" } },
  { eventType: "form_iframe_present",   expectsConversion: false, metadata: { providers: ["jotform"] } },
];

interface EventAcceptanceResult { eventType: string; status: number; ok: boolean; elapsed: number }
interface ConversionCreationResult { eventType: string; conversionFound: boolean; conversionType: string | null }
interface AnalyticsAggregationResult { eventType: string; foundInAggregation: boolean; count: number }
interface AdminMetricFieldResult { field: string; exists: boolean }
interface EventLabelResult { eventType: string; label: string; isHumanized: boolean; inLabelsMap: boolean }

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

  const { searchParams } = new URL(req.url);
  const brandIdParam = searchParams.get("brandId");

  return NextResponse.json(await withAdminTiming("debug.verify-form-tracking", async () => {
    // ── Resolve brand + site ──────────────────────────────────────
    // Default to the first brand WITH a TrackedSite — a brand without
    // one can't accept events through /api/collect at all.
    let brandId: string | null = brandIdParam;
    if (!brandId) {
      const firstBrandWithSite = await prisma.trackedSite.findFirst({
        orderBy: { createdAt: "asc" },
        select: { brandId: true },
      });
      brandId = firstBrandWithSite?.brandId ?? null;
    }
    if (!brandId) {
      return {
        timestamp: new Date().toISOString(),
        error: "No brand with a TrackedSite found. Pass ?brandId=<cuid> or seed at least one TrackedSite first.",
      };
    }

    const trackedSite = await prisma.trackedSite.findUnique({
      where: { brandId },
      select: { id: true, siteId: true, brandId: true, allowedDomains: true },
    });
    if (!trackedSite) {
      return {
        timestamp: new Date().toISOString(),
        brandId,
        error: `No TrackedSite for brand ${brandId}. Install the Site Tag for this brand first.`,
      };
    }

    // /api/collect's domain validator requires the page URL's host to
    // be in the brand's allowedDomains list. Use the first allowed
    // domain as the test page host.
    const testHost = trackedSite.allowedDomains[0] ?? "example.com";
    const testPageUrl = `https://${testHost}${TEST_PAGE_PATH}`;
    const verifyRun = Date.now();
    const testSessionId = `verify-form-tracking-${verifyRun}`;
    const collectUrl = new URL("/api/collect", req.url).toString();
    const platformMetricsUrl = new URL(`/api/admin/platform-metrics?brandId=${brandId}&range=today`, req.url).toString();
    const cookieHeader = req.headers.get("cookie") ?? "";

    // ─── (1) EVENT ACCEPTANCE ─────────────────────────────────────
    const eventAcceptance: EventAcceptanceResult[] = [];
    for (const ev of TEST_EVENTS) {
      const t0 = Date.now();
      const payload = {
        site_id: trackedSite.siteId,
        event_type: ev.eventType,
        page_url: testPageUrl,
        session_id: testSessionId,
        timestamp: new Date().toISOString(),
        // _test + _verifyRun stamps drive the cleanup pass at the end
        // — never deleted by a metadata-less query.
        metadata: { ...ev.metadata, _test: true, _verifyRun: verifyRun },
      };
      let status = 0;
      try {
        const res = await fetch(collectUrl, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(payload),
        });
        status = res.status;
      } catch {
        status = 0;
      }
      eventAcceptance.push({
        eventType: ev.eventType,
        status,
        ok: status === 200,
        elapsed: Date.now() - t0,
      });
    }
    console.info("[verify-form-tracking] event acceptance:", JSON.stringify(eventAcceptance));

    // ─── (2) CONVERSION CREATION ──────────────────────────────────
    // The collect-side SiteConversion writer is fire-and-forget; give
    // it a short window to land before checking.
    await new Promise((r) => setTimeout(r, 500));
    const sixtyAgo = new Date(verifyRun - 60_000);
    const conversionCreation: ConversionCreationResult[] = [];
    for (const ev of TEST_EVENTS) {
      if (!ev.expectsConversion) continue;
      const found = await prisma.siteConversion.findFirst({
        where: {
          brandId: trackedSite.brandId,
          sessionId: testSessionId,
          pageUrl: { contains: TEST_PAGE_PATH },
          conversionType: ev.expectedConversionType ?? undefined,
          timestamp: { gte: sixtyAgo },
        },
        select: { id: true, conversionType: true },
        orderBy: { timestamp: "desc" },
      });
      conversionCreation.push({
        eventType: ev.eventType,
        conversionFound: !!found,
        conversionType: found?.conversionType ?? null,
      });
    }
    console.info("[verify-form-tracking] conversion creation:", JSON.stringify(conversionCreation));

    // ─── (3) ANALYTICS AGGREGATION ────────────────────────────────
    // Query TrackedEvent directly, grouped by eventType, restricted to
    // the synthetic test page URL and the last 5 minutes. Direct DB
    // read is more reliable than calling the analytics service (which
    // doesn't filter by pageUrl).
    const fiveAgo = new Date(verifyRun - 5 * 60_000);
    const groupedRaw = await prisma.trackedEvent.groupBy({
      by: ["eventType"],
      where: {
        trackedSiteId: trackedSite.id,
        pageUrl: { contains: TEST_PAGE_PATH },
        timestamp: { gte: fiveAgo },
      },
      _count: { eventType: true },
    });
    const grouped = new Map(groupedRaw.map((g) => [g.eventType, g._count.eventType]));
    const analyticsAggregation: AnalyticsAggregationResult[] = TEST_EVENTS.map((ev) => {
      const count = grouped.get(ev.eventType) ?? 0;
      return {
        eventType: ev.eventType,
        foundInAggregation: count >= 1,
        count,
      };
    });
    console.info("[verify-form-tracking] analytics aggregation:", JSON.stringify(analyticsAggregation));

    // ─── (4) ADMIN METRIC FIELDS ──────────────────────────────────
    // Hit the platform-metrics route with the user's session cookie
    // (superadmin gated) and check the response carries the new
    // fields. We don't care about counts here — the test events are
    // already counted in (3) — only that the schema is correct.
    const fieldsToCheck = ["formSubmits", "bookings", "formStarts", "conversions", "phoneCalls", "outboundClicks"];
    let metricsJson: { metrics?: Record<string, unknown> } | null = null;
    try {
      const res = await fetch(platformMetricsUrl, {
        headers: { Cookie: cookieHeader },
      });
      if (res.ok) {
        metricsJson = (await res.json()) as { metrics?: Record<string, unknown> };
      }
    } catch (err) {
      console.warn("[verify-form-tracking] platform-metrics fetch failed", err);
    }
    const metricsBag = metricsJson?.metrics ?? {};
    const adminMetricFields: AdminMetricFieldResult[] = fieldsToCheck.map((field) => ({
      field,
      exists: Object.prototype.hasOwnProperty.call(metricsBag, field),
    }));

    // ─── (5) EVENT LABELS ─────────────────────────────────────────
    // For each new event type, verify a humanised label is exposed.
    // We check both:
    //   - eventTypeLabel(t) !== t   (the spec's literal check)
    //   - t exists in EVENT_TYPE_LABELS (strict — distinguishes a
    //     deliberate label from the snake_case→Title fallback)
    const eventLabels: EventLabelResult[] = TEST_EVENTS.map((ev) => {
      const label = eventTypeLabel(ev.eventType);
      return {
        eventType: ev.eventType,
        label,
        isHumanized: label !== ev.eventType,
        inLabelsMap: Object.prototype.hasOwnProperty.call(EVENT_TYPE_LABELS, ev.eventType),
      };
    });

    // ─── (6) CLEANUP ──────────────────────────────────────────────
    // Strict match — only delete rows whose metadata.{_test, _verifyRun}
    // fields point at THIS run. Composite filter on _verifyRun
    // (millisecond timestamp) makes a collision astronomically
    // unlikely even if real data shares the page URL.
    let trackedEventsDeleted = 0;
    let conversionsDeleted = 0;
    try {
      const trackedDel = await prisma.trackedEvent.deleteMany({
        where: {
          trackedSiteId: trackedSite.id,
          pageUrl: { contains: TEST_PAGE_PATH },
          metadata: { path: ["_verifyRun"], equals: verifyRun },
        },
      });
      trackedEventsDeleted = trackedDel.count;
    } catch (err) {
      console.warn("[verify-form-tracking] TrackedEvent cleanup failed", err);
    }
    try {
      const convDel = await prisma.siteConversion.deleteMany({
        where: {
          brandId: trackedSite.brandId,
          sessionId: testSessionId,
          pageUrl: { contains: TEST_PAGE_PATH },
          timestamp: { gte: fiveAgo },
        },
      });
      conversionsDeleted = convDel.count;
    } catch (err) {
      console.warn("[verify-form-tracking] SiteConversion cleanup failed", err);
    }

    // ─── (7) BUILD SUMMARY ────────────────────────────────────────
    const checks = [
      ...eventAcceptance.map((r) => r.ok),
      ...conversionCreation.map((r) => r.conversionFound),
      ...analyticsAggregation.map((r) => r.foundInAggregation),
      ...adminMetricFields.map((r) => r.exists),
      ...eventLabels.map((r) => r.isHumanized),
    ];
    const totalTests = checks.length;
    const passed = checks.filter(Boolean).length;
    const failed = totalTests - passed;
    const verdict = failed === 0 ? "ALL PASS" : `${failed} FAILURE${failed === 1 ? "" : "S"}`;

    const summary = { totalTests, passed, failed, verdict };
    console.info("[verify-form-tracking] summary:", JSON.stringify(summary));

    return {
      timestamp: new Date().toISOString(),
      brandId: trackedSite.brandId,
      siteId: trackedSite.siteId,
      results: {
        eventAcceptance,
        conversionCreation,
        analyticsAggregation,
        adminMetricFields,
        eventLabels,
        cleanup: { trackedEventsDeleted, conversionsDeleted },
      },
      summary,
    };
  }));
}
