/**
 * Revenue Attribution — First-Party Revenue Aggregation Service
 * ─────────────────────────────────────────────────────────────
 * Queries SiteConversion (with conversionValue) joined to AiAttribution
 * for AI engine revenue attribution. 1st-party only — returns null when
 * brandId is absent or no SiteConversion rows exist in the window.
 *
 * Internal module — no third-party vendor names in user-facing output.
 */

import { Prisma } from "@prisma/client";
import { prisma } from "@/lib/prisma";
import type { RevenueAttribution } from "../types";

// ─── Helpers ──────────────────────────────────────────────────────────────────

function safeDivide(n: number, d: number): number {
  return d === 0 ? 0 : n / d;
}

function roundMoney(n: number): number {
  return Math.round(n * 100) / 100;
}

function roundPct(n: number): number {
  return Math.round(n * 10) / 10;
}

// Map internal classifiedChannel values → user-facing channel group names
function normalizeChannel(ch: string | null | undefined): string {
  switch (ch) {
    case "ai_assistant": return "AI";
    case "organic_search": return "Organic Search";
    case "paid_search":
    case "paid_social":
    case "display":
    case "affiliate": return "Paid";
    case "direct": return "Direct";
    case "referral":
    case "organic_social":
    case "email":
    case "video":
    case "local_maps": return "Referral";
    default: return "Other";
  }
}

// Normalize raw aiPlatform → display name (AI engine references are allowed)
function aiEngineDisplayName(raw: string): string {
  const lower = raw.toLowerCase();
  if (lower.includes("chatgpt") || lower.includes("openai") || lower.includes("gpt")) return "ChatGPT";
  if (lower.includes("perplexity")) return "Perplexity";
  if (lower.includes("gemini") || lower.includes("bard")) return "Gemini";
  if (lower.includes("copilot") || lower.includes("bing")) return "Microsoft Copilot";
  if (lower.includes("claude")) return "Claude";
  return raw;
}

function fmtUsd(n: number): string {
  return `$${n.toLocaleString("en-US", { minimumFractionDigits: 0, maximumFractionDigits: 0 })}`;
}

// ─── Row types ────────────────────────────────────────────────────────────────

type ConvRow = {
  id: string;
  sessionId: string;
  conversionValue: number | null;
  classifiedChannel: string | null;
  pageUrl: string;
};

type AiConvRow = {
  id: string;
  conversionValue: number;
  aiPlatform: string;
  landingPage: string;
};

type PriorRow = {
  classifiedChannel: string | null;
  total_revenue: number;
  conversions: number;
};

// ─── Constants ────────────────────────────────────────────────────────────────

const PATENT_RELEVANCE =
  "Cookieless attribution enabled by the meSEO Site Tag identifies revenue sources that traditional analytics misattribute to direct or unknown channels, including all AI engine traffic.";

const FUTURE_CAPABILITIES: RevenueAttribution["futureCapabilities"] = {
  cacAvailable: false,
  ltvAvailable: false,
  cacNote: "Customer Acquisition Cost available when marketing spend integration is enabled",
  ltvNote: "Lifetime Value approximation available with 90+ days of historical revenue data",
};

// ─── Main export ──────────────────────────────────────────────────────────────

export async function aggregateRevenueAttribution(
  brandId: string,
  windowDays = 30,
  priorWindowDays = 30,
): Promise<RevenueAttribution | null> {
  const since = new Date(Date.now() - windowDays * 24 * 60 * 60 * 1000);
  const priorStart = new Date(Date.now() - (windowDays + priorWindowDays) * 24 * 60 * 60 * 1000);
  const priorEnd = since;

  // Fetch all deduped, valid conversions in window (revenue-bearing + non-revenue)
  let allConversions: ConvRow[];
  try {
    // intentionally unfiltered: audit report; needs broader conversion history
    allConversions = await prisma.siteConversion.findMany({
      where: {
        brandId,
        timestamp: { gte: since },
        isDuplicateOf: null,
        invalidatedReason: null,
      },
      select: {
        id: true,
        sessionId: true,
        conversionValue: true,
        classifiedChannel: true,
        pageUrl: true,
      },
    });
  } catch (err) {
    console.warn("[revenue-attribution] failed to fetch conversions:", err instanceof Error ? err.message : err);
    return null;
  }

  const totalConversions = allConversions.length;
  if (totalConversions === 0) return null;

  const revenueConversions = allConversions.filter((c) => c.conversionValue != null);
  const totalConversionsWithRevenue = revenueConversions.length;
  const conversionsMissingRevenue = totalConversions - totalConversionsWithRevenue;
  const revenueTrackingCoveragePercent = roundPct(safeDivide(totalConversionsWithRevenue, totalConversions) * 100);

  // No revenue values tracked yet → return placeholder shell
  if (totalConversionsWithRevenue === 0) {
    return {
      hasRevenueTracking: false,
      windowDays,
      dataConfidence: "insufficient",
      aggregateMetrics: {
        totalRevenueTracked: 0,
        totalConversionsWithRevenue: 0,
        avgRevenuePerConversion: 0,
        conversionsMissingRevenue,
        revenueTrackingCoveragePercent: 0,
      },
      revenueByChannel: [],
      revenueByAiEngine: [],
      topRevenuePages: [],
      insights: [],
      patentRelevance: PATENT_RELEVANCE,
      futureCapabilities: FUTURE_CAPABILITIES,
    };
  }

  const totalRevenueTracked = roundMoney(
    revenueConversions.reduce((s, c) => s + (c.conversionValue ?? 0), 0),
  );
  const avgRevenuePerConversion = roundMoney(
    safeDivide(totalRevenueTracked, totalConversionsWithRevenue),
  );

  const dataConfidence: RevenueAttribution["dataConfidence"] =
    totalConversionsWithRevenue >= 100 ? "high"
    : totalConversionsWithRevenue >= 21 ? "moderate"
    : totalConversionsWithRevenue >= 5 ? "low"
    : "insufficient";

  // ─── Channel revenue breakdown ─────────────────────────────────────────────

  const channelRevMap: Record<string, { revenue: number; conversions: number }> = {};
  for (const c of revenueConversions) {
    const ch = normalizeChannel(c.classifiedChannel);
    if (!channelRevMap[ch]) channelRevMap[ch] = { revenue: 0, conversions: 0 };
    channelRevMap[ch].revenue += c.conversionValue!;
    channelRevMap[ch].conversions++;
  }

  // ─── Prior period (for period-over-period deltas) ──────────────────────────

  let priorRows: PriorRow[] = [];
  try {
    priorRows = await prisma.$queryRaw<PriorRow[]>(Prisma.sql`
      SELECT "classifiedChannel",
             SUM("conversionValue")::float AS total_revenue,
             COUNT(*)::int                AS conversions
      FROM "SiteConversion"
      WHERE "brandId" = ${brandId}
        AND "timestamp" >= ${priorStart} AND "timestamp" < ${priorEnd}
        AND "isDuplicateOf" IS NULL AND "invalidatedReason" IS NULL
        AND "conversionValue" IS NOT NULL
      GROUP BY "classifiedChannel"
    `);
  } catch (err) {
    console.warn("[revenue-attribution] prior period query failed (non-fatal):", err instanceof Error ? err.message : err);
  }

  const priorChannelMap: Record<string, { revenue: number; conversions: number }> = {};
  for (const row of priorRows) {
    const ch = normalizeChannel(row.classifiedChannel);
    if (!priorChannelMap[ch]) priorChannelMap[ch] = { revenue: 0, conversions: 0 };
    priorChannelMap[ch].revenue += row.total_revenue ?? 0;
    priorChannelMap[ch].conversions += row.conversions;
  }

  const revenueByChannel: RevenueAttribution["revenueByChannel"] = Object.entries(channelRevMap)
    .sort(([, a], [, b]) => b.revenue - a.revenue)
    .map(([channelName, data]) => {
      const prior = priorChannelMap[channelName];
      const hasPrior = prior && prior.revenue > 0;
      return {
        channelName,
        revenue: roundMoney(data.revenue),
        sharePercent: roundPct(safeDivide(data.revenue, totalRevenueTracked) * 100),
        conversions: data.conversions,
        avgRevenuePerConversion: roundMoney(safeDivide(data.revenue, data.conversions)),
        deltaVsPrior30d: hasPrior
          ? {
              revenueDelta: roundMoney(data.revenue - prior.revenue),
              revenueDeltaPercent: roundPct(((data.revenue - prior.revenue) / prior.revenue) * 100),
              conversionsDelta: data.conversions - prior.conversions,
            }
          : null,
      };
    });

  // ─── AI engine revenue breakdown ───────────────────────────────────────────

  let aiConvRows: AiConvRow[] = [];
  try {
    aiConvRows = await prisma.$queryRaw<AiConvRow[]>(Prisma.sql`
      SELECT sc."id",
             sc."conversionValue"::float AS "conversionValue",
             aa."aiPlatform",
             aa."landingPage"
      FROM "SiteConversion" sc
      JOIN (
        SELECT DISTINCT ON ("sessionId")
               "sessionId", "aiPlatform", "landingPage"
        FROM "AiAttribution"
        WHERE "brandId" = ${brandId}
          AND "timestamp" >= ${since}
          AND "aiPlatform" IS NOT NULL
        ORDER BY "sessionId", "timestamp" DESC
      ) aa ON sc."sessionId" = aa."sessionId"
      WHERE sc."brandId" = ${brandId}
        AND sc."timestamp" >= ${since}
        AND sc."isDuplicateOf" IS NULL
        AND sc."invalidatedReason" IS NULL
        AND sc."conversionValue" IS NOT NULL
    `);
  } catch (err) {
    console.warn("[revenue-attribution] AI engine join query failed (non-fatal):", err instanceof Error ? err.message : err);
  }

  const totalAiRevenue = aiConvRows.reduce((s, r) => s + r.conversionValue, 0);
  const engineMap: Record<string, { revenue: number; conversions: number; pageRevenue: Record<string, number> }> = {};
  for (const row of aiConvRows) {
    const engine = aiEngineDisplayName(row.aiPlatform);
    if (!engineMap[engine]) engineMap[engine] = { revenue: 0, conversions: 0, pageRevenue: {} };
    engineMap[engine].revenue += row.conversionValue;
    engineMap[engine].conversions++;
    engineMap[engine].pageRevenue[row.landingPage] = (engineMap[engine].pageRevenue[row.landingPage] ?? 0) + row.conversionValue;
  }

  const revenueByAiEngine: RevenueAttribution["revenueByAiEngine"] = Object.entries(engineMap)
    .sort(([, a], [, b]) => b.revenue - a.revenue)
    .map(([engineName, data]) => {
      const highestRevenueLandingPage =
        Object.entries(data.pageRevenue).sort(([, a], [, b]) => b - a)[0]?.[0] ?? null;
      return {
        engineName,
        revenue: roundMoney(data.revenue),
        shareOfAiRevenuePercent: roundPct(safeDivide(data.revenue, totalAiRevenue) * 100),
        shareOfTotalRevenuePercent: roundPct(safeDivide(data.revenue, totalRevenueTracked) * 100),
        conversions: data.conversions,
        avgRevenuePerConversion: roundMoney(safeDivide(data.revenue, data.conversions)),
        highestRevenueLandingPage,
      };
    });

  // ─── Top revenue pages ─────────────────────────────────────────────────────

  const pageMap: Record<string, { revenue: number; conversions: number; channels: Record<string, number> }> = {};
  for (const c of revenueConversions) {
    const page = c.pageUrl;
    if (!pageMap[page]) pageMap[page] = { revenue: 0, conversions: 0, channels: {} };
    pageMap[page].revenue += c.conversionValue!;
    pageMap[page].conversions++;
    const ch = normalizeChannel(c.classifiedChannel);
    pageMap[page].channels[ch] = (pageMap[page].channels[ch] ?? 0) + 1;
  }

  const topRevenuePages: RevenueAttribution["topRevenuePages"] = Object.entries(pageMap)
    .sort(([, a], [, b]) => b.revenue - a.revenue)
    .slice(0, 10)
    .map(([pageUrl, data]) => {
      const dominantReferringChannel =
        Object.entries(data.channels).sort(([, a], [, b]) => b - a)[0]?.[0] ?? "Other";
      return {
        pageUrl,
        revenue: roundMoney(data.revenue),
        conversions: data.conversions,
        avgRevenuePerConversion: roundMoney(safeDivide(data.revenue, data.conversions)),
        dominantReferringChannel,
        sharePercent: roundPct(safeDivide(data.revenue, totalRevenueTracked) * 100),
      };
    });

  // ─── Insights ──────────────────────────────────────────────────────────────

  const insights: RevenueAttribution["insights"] = [];

  const topChannel = revenueByChannel[0];
  if (topChannel) {
    insights.push({
      insight: `${topChannel.channelName} is the top revenue channel at ${fmtUsd(topChannel.revenue)} (${topChannel.sharePercent}% of tracked revenue)`,
      supportingMetric: `${topChannel.conversions} conversions at avg ${fmtUsd(topChannel.avgRevenuePerConversion)} per conversion`,
      businessImplication: `Protecting and amplifying ${topChannel.channelName} channel performance is the highest-priority revenue lever in the audit window.`,
    });
  }

  const bestRpvChannel = [...revenueByChannel]
    .filter((c) => c.conversions >= 3)
    .sort((a, b) => b.avgRevenuePerConversion - a.avgRevenuePerConversion)[0];
  if (bestRpvChannel && bestRpvChannel.channelName !== topChannel?.channelName) {
    const multiplier = roundPct(safeDivide(bestRpvChannel.avgRevenuePerConversion, avgRevenuePerConversion) * 100);
    insights.push({
      insight: `${bestRpvChannel.channelName} delivers the highest revenue per conversion at ${fmtUsd(bestRpvChannel.avgRevenuePerConversion)}, ${multiplier}% of the overall average`,
      supportingMetric: `${bestRpvChannel.conversions} conversions, ${fmtUsd(bestRpvChannel.revenue)} total revenue`,
      businessImplication: `Growing ${bestRpvChannel.channelName} volume would yield above-average revenue density — prioritize content and visibility investments that strengthen this channel.`,
    });
  }

  if (revenueByAiEngine.length > 0) {
    const topEngine = revenueByAiEngine[0]!;
    insights.push({
      insight: `${topEngine.engineName} is the highest-revenue AI engine at ${fmtUsd(topEngine.revenue)} (${topEngine.shareOfTotalRevenuePercent}% of total tracked revenue)`,
      supportingMetric: `${topEngine.conversions} conversions at avg ${fmtUsd(topEngine.avgRevenuePerConversion)} per conversion`,
      businessImplication: `Schema and content optimization targeting ${topEngine.engineName} citation eligibility represents a direct revenue protection priority.`,
    });
  }

  const topPage = topRevenuePages[0];
  if (topPage && topPage.sharePercent >= 20) {
    insights.push({
      insight: `${topPage.pageUrl} accounts for ${topPage.sharePercent}% of attributable revenue — the single highest-revenue conversion page`,
      supportingMetric: `${topPage.conversions} conversions, ${fmtUsd(topPage.revenue)} total, avg ${fmtUsd(topPage.avgRevenuePerConversion)} per conversion`,
      businessImplication: `Technical health, schema coverage, and AI citation eligibility on this page represent the most direct revenue lever. Any visibility drop on this URL has an outsized revenue impact.`,
    });
  }

  if (revenueTrackingCoveragePercent < 80 && conversionsMissingRevenue > 5) {
    insights.push({
      insight: `Revenue tracking covers ${revenueTrackingCoveragePercent}% of conversions — ${conversionsMissingRevenue} conversions are missing revenue values`,
      supportingMetric: `${totalConversionsWithRevenue} of ${totalConversions} total conversions have revenue tracked`,
      businessImplication: `Adding revenue event values to non-purchase conversion types would provide a more complete attribution picture and enable Customer Acquisition Cost calculation.`,
    });
  }

  return {
    hasRevenueTracking: true,
    windowDays,
    dataConfidence,
    aggregateMetrics: {
      totalRevenueTracked,
      totalConversionsWithRevenue,
      avgRevenuePerConversion,
      conversionsMissingRevenue,
      revenueTrackingCoveragePercent,
    },
    revenueByChannel,
    revenueByAiEngine,
    topRevenuePages,
    insights: insights.slice(0, 5),
    patentRelevance: PATENT_RELEVANCE,
    futureCapabilities: FUTURE_CAPABILITIES,
  };
}
