/**
 * AI Channel Forecasting
 * ──────────────────────
 * Projects future AI attribution performance based on historical
 * data using linear regression with growth decay.
 */

import { prisma } from "@/lib/prisma";

export interface AiForecast {
  period: string;
  projectedReferrals: number;
  projectedConversions: number;
  projectedRevenue: number;
  confidence: "high" | "medium" | "low";
  methodology: string;
  assumptions: string[];
}

export interface ForecastSummary {
  forecasts: AiForecast[];
  dataMonths: number;
  confidence: "high" | "medium" | "low";
  headline: string;
  caveat: string | null;
}

export async function generateAiForecast(
  brandId: string,
  monthsToForecast = 6,
): Promise<ForecastSummary> {
  const monthly = await getMonthlyData(brandId);

  if (monthly.length < 1) {
    return {
      forecasts: [],
      dataMonths: 0,
      confidence: "low",
      headline: "Not enough data for forecasting. Projections will be available after 30 days of AI traffic data.",
      caveat: null,
    };
  }

  const dataMonths = monthly.length;
  const confidence: "high" | "medium" | "low" =
    dataMonths >= 6 ? "high" : dataMonths >= 3 ? "medium" : "low";

  const avgDealValue = await getTrailingDealValue(brandId);

  const referralGrowth = calculateGrowthRate(monthly.map((m) => m.referrals));
  const convRateTrend = calculateConvRateAvg(monthly);

  const lastMonth = monthly[monthly.length - 1];
  const forecasts: AiForecast[] = [];

  const now = new Date();
  for (let i = 1; i <= monthsToForecast; i++) {
    const targetDate = new Date(now.getFullYear(), now.getMonth() + i, 1);
    const period = `${targetDate.toLocaleString("en-US", { month: "short" })} ${targetDate.getFullYear()}`;

    const decayedGrowth = referralGrowth * Math.pow(0.9, i - 1);
    const projectedReferrals = Math.round(lastMonth.referrals * Math.pow(1 + decayedGrowth, i));
    const projectedConversions = Math.round(projectedReferrals * convRateTrend);
    const projectedRevenue = Math.round(projectedConversions * avgDealValue);

    forecasts.push({
      period,
      projectedReferrals: Math.max(0, projectedReferrals),
      projectedConversions: Math.max(0, projectedConversions),
      projectedRevenue: Math.max(0, projectedRevenue),
      confidence,
      methodology: dataMonths >= 6 ? "growth_curve" : "linear_regression",
      assumptions: [
        `${Math.round(decayedGrowth * 100)}% monthly referral growth (decaying)`,
        `${Math.round(convRateTrend * 100)}% conversion rate`,
        `$${avgDealValue.toLocaleString()} average deal value`,
      ],
    });
  }

  const lastForecast = forecasts[forecasts.length - 1];
  const headline = lastForecast
    ? `At current growth rate, AI-attributed revenue is projected to reach $${lastForecast.projectedRevenue.toLocaleString()}/month by ${lastForecast.period}`
    : "Insufficient data for projections.";

  const caveat = confidence === "low"
    ? "Early forecast (low confidence) — projections will improve with more data."
    : confidence === "medium"
      ? "Medium confidence forecast — accuracy improves with 6+ months of data."
      : null;

  return { forecasts, dataMonths, confidence, headline, caveat };
}

export interface WhatIfScenario {
  label: string;
  adjustedRevenue: number;
  delta: number;
  description: string;
}

export async function runWhatIfScenarios(
  brandId: string,
): Promise<WhatIfScenario[]> {
  const forecast = await generateAiForecast(brandId, 3);
  if (forecast.forecasts.length === 0) return [];

  const baseline = forecast.forecasts[0];
  const scenarios: WhatIfScenario[] = [];

  const monthly = await getMonthlyData(brandId);
  if (monthly.length === 0) return [];

  const avgReferralsPerPage = monthly[monthly.length - 1].referrals / Math.max(1, await getCitedPageCount(brandId));
  const avgDealValue = await getTrailingDealValue(brandId);
  const convRate = calculateConvRateAvg(monthly);

  const extraPages10 = Math.round(10 * avgReferralsPerPage);
  const extraConv10 = Math.round(extraPages10 * convRate);
  const extraRev10 = Math.round(extraConv10 * avgDealValue);
  scenarios.push({
    label: "Optimize 10 more pages for AI",
    adjustedRevenue: baseline.projectedRevenue + extraRev10,
    delta: extraRev10,
    description: `+${extraPages10} estimated referrals, +${extraConv10} conversions, +$${extraRev10.toLocaleString()}/month`,
  });

  const improvedConvRate = Math.min(convRate + 0.05, 1);
  const improvedConv = Math.round(baseline.projectedReferrals * improvedConvRate);
  const improvedRev = Math.round(improvedConv * avgDealValue);
  scenarios.push({
    label: "Improve AI conversion rate by 5%",
    adjustedRevenue: improvedRev,
    delta: improvedRev - baseline.projectedRevenue,
    description: `Conv rate ${Math.round(convRate * 100)}% → ${Math.round(improvedConvRate * 100)}%, +$${(improvedRev - baseline.projectedRevenue).toLocaleString()}/month`,
  });

  const platformBoost = Math.round(baseline.projectedReferrals * 0.15);
  const platformConv = Math.round(platformBoost * convRate);
  const platformRev = Math.round(platformConv * avgDealValue);
  scenarios.push({
    label: "New AI platform starts sending traffic",
    adjustedRevenue: baseline.projectedRevenue + platformRev,
    delta: platformRev,
    description: `+15% referrals from new platform, +$${platformRev.toLocaleString()}/month`,
  });

  return scenarios;
}

// ─── Data Aggregation ──────────────────────────────────────────────────────

interface MonthlyBucket {
  month: string;
  referrals: number;
  conversions: number;
  revenue: number;
}

async function getMonthlyData(brandId: string): Promise<MonthlyBucket[]> {
  const d365 = new Date(Date.now() - 365 * 86_400_000);

  const attributions = await prisma.aiAttribution.findMany({
    where: { brandId, timestamp: { gte: d365 } },
    select: { timestamp: true, converted: true, dealValue: true },
    orderBy: { timestamp: "asc" },
  });

  if (attributions.length === 0) return [];

  const buckets = new Map<string, MonthlyBucket>();
  for (const a of attributions) {
    const month = `${a.timestamp.getFullYear()}-${String(a.timestamp.getMonth() + 1).padStart(2, "0")}`;
    const bucket = buckets.get(month) ?? { month, referrals: 0, conversions: 0, revenue: 0 };
    bucket.referrals++;
    if (a.converted) {
      bucket.conversions++;
      bucket.revenue += a.dealValue ?? 0;
    }
    buckets.set(month, bucket);
  }

  return [...buckets.values()].sort((a, b) => a.month.localeCompare(b.month));
}

async function getTrailingDealValue(brandId: string): Promise<number> {
  const d90 = new Date(Date.now() - 90 * 86_400_000);
  const result = await prisma.aiAttribution.aggregate({
    where: { brandId, timestamp: { gte: d90 }, dealValue: { gt: 0 } },
    _avg: { dealValue: true },
  }).catch(() => ({ _avg: { dealValue: null } }));
  return result._avg.dealValue ?? 500;
}

async function getCitedPageCount(brandId: string): Promise<number> {
  const d30 = new Date(Date.now() - 30 * 86_400_000);
  const pages = await prisma.aiAttribution.groupBy({
    by: ["landingPage"],
    where: { brandId, timestamp: { gte: d30 } },
  }).catch(() => []);
  return Math.max(pages.length, 1);
}

function calculateGrowthRate(values: number[]): number {
  if (values.length < 2) return 0.1;
  const rates: number[] = [];
  for (let i = 1; i < values.length; i++) {
    if (values[i - 1] > 0) {
      rates.push((values[i] - values[i - 1]) / values[i - 1]);
    }
  }
  if (rates.length === 0) return 0.1;
  const avg = rates.reduce((s, r) => s + r, 0) / rates.length;
  return Math.max(-0.2, Math.min(avg, 0.5));
}

function calculateConvRateAvg(monthly: MonthlyBucket[]): number {
  const totalRefs = monthly.reduce((s, m) => s + m.referrals, 0);
  const totalConv = monthly.reduce((s, m) => s + m.conversions, 0);
  return totalRefs > 0 ? totalConv / totalRefs : 0.1;
}
