/**
 * SHARED METRICS — Single source of truth for cross-page data consistency
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * MESEO DATA SOURCES:
 *
 * Site Tag (first-party, meSEO-collected):
 *   - TrackedEvent: raw events (page_view, session_start, form_start, etc.)
 *   - TrackedSession: session records (one per browser session)
 *   - SiteConversion: deduped conversion records (30-second resolver)
 *   - SiteEvent: aggregated/signal events (used by Signals Center)
 *
 * GA4 (Google Analytics, third-party):
 *   - MetricSnapshot (source="ga4"): daily sessions, users, pageViews, keyEvents
 *   - Note: GA4 "key events" ≠ Site Tag "conversions". GA4 counts EVENT
 *     occurrences (one session can fire 5 key events), Site Tag counts
 *     UNIQUE converting sessions (deduped per 30-second window).
 *
 * GSC (Google Search Console):
 *   - MetricSnapshot (source="gsc"): daily clicks, impressions, position, ctr
 *   - GscPage: per-page GSC metrics
 *   - GscQuery: per-keyword GSC metrics
 *   - KeywordRanking: tracked keyword positions from DataForSEO
 *
 * RULES:
 *   1. "Conversions" ALWAYS means Site Tag SiteConversion (deduped)
 *      unless explicitly labeled "GA4 Key Events"
 *   2. "Sessions" defaults to Site Tag (TrackedEvent session_start)
 *      unless labeled "GA4 Sessions"
 *   3. All queries within a single request must use the SAME from/to
 *      dates (capture `new Date()` ONCE, pass to all sub-queries)
 *   4. The conversion funnel's "Total Conversions" must equal the
 *      overview KPI's "Total Conversions" — both use getConversionSummary()
 *   5. "Active Pages" = COUNT(DISTINCT normalized_pageUrl) from TrackedEvent
 *      (normalized = query params + fragments stripped)
 *   6. "AI Referrals" = AiAttribution count for the date range
 *
 * CONSISTENCY GUARANTEE:
 *   Within Site Tag Analytics, ALL tabs (Overview, Conversions, Funnel,
 *   Attribution, AI Attribution) render from the SAME fetched data object
 *   stored in the parent page's React state. They can't diverge because
 *   they read the same value.
 *
 * KNOWN LEGITIMATE DIFFERENCES (not bugs):
 *   - Dashboard "Sessions" (from MetricSnapshot GA4) ≠ Site Tag "Sessions"
 *     (from TrackedEvent session_start). Different collection methods.
 *   - Content Intel "Pages" (crawled+analyzed) ≠ "Active Pages" (pages
 *     with page_view events). A page can have events without being crawled,
 *     or crawled without having recent events.
 *   - Admin Historical totals are cumulative all-time, not range-limited.
 */

import { prisma } from "@/lib/prisma";
import { countedConversionWhere } from "@/lib/conversions/counted-where";

/**
 * Site Tag Conversions — the authoritative deduped conversion count.
 * Every surface that displays "X conversions" for the Site Tag should
 * call this or getConversionSummary() which wraps similar logic.
 */
export async function getSiteTagConversions(
  brandId: string,
  from: Date,
  to: Date,
): Promise<{
  totalConversions: number;
  totalInteractions: number;
  duplicatesCaught: number;
  byType: Record<string, number>;
}> {
  const [conversions, interactions] = await Promise.all([
    prisma.siteConversion.count({
      where: countedConversionWhere(brandId, { since: from, until: to }),
    }),
    prisma.trackedEvent.count({
      where: {
        trackedSite: { brandId },
        eventType: { in: [
          "form_submit", "click_to_call", "phone_call", "phone_number_click",
          "booking_confirmed", "booking_submit", "purchase", "purchase_completed",
          "sms_click", "sms_submit", "email_click",
        ] },
        timestamp: { gte: from, lte: to },
      },
    }),
  ]);

  const byTypeRaw = await prisma.siteConversion.groupBy({
    by: ["conversionType"],
    where: countedConversionWhere(brandId, { since: from, until: to }),
    _count: true,
  }).catch(() => []);

  const byType: Record<string, number> = {};
  for (const r of byTypeRaw) {
    byType[r.conversionType] = typeof r._count === "number" ? r._count : 0;
  }

  return {
    totalConversions: conversions,
    totalInteractions: interactions,
    duplicatesCaught: Math.max(0, interactions - conversions),
    byType,
  };
}

/**
 * Site Tag Sessions — counted from TrackedEvent session_start events.
 * Matches the Overview tab's "Session Start" tile and the AI Attribution
 * tab's "Sessions Scanned" counter.
 */
export async function getSiteTagSessions(
  brandId: string,
  from: Date,
  to: Date,
): Promise<number> {
  const site = await prisma.trackedSite.findUnique({
    where: { brandId },
    select: { id: true },
  });
  if (!site) return 0;
  return prisma.trackedEvent.count({
    where: {
      trackedSiteId: site.id,
      eventType: "session_start",
      timestamp: { gte: from, lte: to },
    },
  });
}

/**
 * GA4 Metrics — from MetricSnapshot. Intentionally separate from
 * Site Tag metrics. Label as "GA4" whenever displayed.
 */
export async function getGa4Metrics(
  brandId: string,
  from: Date,
  to: Date,
): Promise<{
  sessions: number;
  users: number;
  keyEvents: number;
  revenue: number;
}> {
  const agg = await prisma.metricSnapshot.aggregate({
    where: { brandId, date: { gte: from, lte: to }, source: "ga4" },
    _sum: { sessions: true, users: true, conversions: true, revenue: true },
  }).catch(() => ({ _sum: { sessions: null, users: null, conversions: null, revenue: null } }));

  return {
    sessions: agg._sum.sessions ?? 0,
    users: agg._sum.users ?? 0,
    keyEvents: agg._sum.conversions ?? 0,
    revenue: agg._sum.revenue ?? 0,
  };
}

/**
 * AI Attribution count — matches the AI Attribution tab KPI.
 */
export async function getAiReferrals(
  brandId: string,
  from: Date,
  to: Date,
): Promise<number> {
  return prisma.aiAttribution.count({
    where: { brandId, timestamp: { gte: from, lte: to } },
  }).catch(() => 0);
}
