import { prisma } from "@/lib/prisma";
import { getDateRange, getComparisonRange, DateRange, CompareMode } from "./date-utils";

export type AttributionModel = "first_touch" | "last_touch" | "assisted";

/**
 * Get revenue attribution data for a brand.
 */
export async function getRevenueAttribution(
  brandId: string,
  range: DateRange = "30d",
  model: AttributionModel = "last_touch",
  compare: CompareMode = "previous"
) {
  const { start, end } = getDateRange(range);
  const comp = getComparisonRange(start, end, compare);

  const current = await prisma.revenueAttribution.findMany({
    where: { brandId, attributionModel: model, date: { gte: start, lte: end } },
    include: { deal: { select: { id: true, dealName: true, value: true, status: true } } },
    orderBy: { date: "desc" },
  });

  const previous = await prisma.revenueAttribution.findMany({
    where: { brandId, attributionModel: model, date: { gte: comp.start, lte: comp.end } },
  });

  // By channel
  const byChannel = groupAndSum(current, "channel");
  const prevByChannel = groupAndSum(previous, "channel");

  // By page
  const byPage = groupAndSum(current.filter((r) => r.landingPage), "landingPage");

  // By conversion type
  const byType = groupAndSum(current.filter((r) => r.conversionType), "conversionType");

  // Totals
  const totalRevenue = Math.round(current.reduce((s, r) => s + r.revenue, 0));
  const prevTotalRevenue = Math.round(previous.reduce((s, r) => s + r.revenue, 0));

  return {
    period: { start, end, range, model, compare },
    totals: {
      revenue: totalRevenue,
      records: current.length,
      revenueChange: totalRevenue - prevTotalRevenue,
      revenueChangePct: prevTotalRevenue > 0 ? Math.round(((totalRevenue - prevTotalRevenue) / prevTotalRevenue) * 100) : 0,
    },
    byChannel: Object.entries(byChannel).map(([channel, data]) => ({
      channel,
      ...data,
      change: (prevByChannel[channel]?.revenue ?? 0) > 0
        ? Math.round(((data.revenue - (prevByChannel[channel]?.revenue ?? 0)) / (prevByChannel[channel]?.revenue ?? 1)) * 100)
        : 0,
    })).sort((a, b) => b.revenue - a.revenue),
    byPage: Object.entries(byPage).map(([page, data]) => ({
      page,
      ...data,
    })).sort((a, b) => b.revenue - a.revenue).slice(0, 10),
    byType: Object.entries(byType).map(([type, data]) => ({
      type,
      ...data,
    })).sort((a, b) => b.revenue - a.revenue),
  };
}

/**
 * Create attribution records from conversion events.
 * This is the "closed loop" — maps conversions to revenue.
 */
export async function attributeConversions(
  brandId: string,
  model: AttributionModel = "last_touch"
) {
  // Get conversions with value (from CRM deals or estimated)
  const conversions = await prisma.conversionEvent.findMany({
    where: { brandId, value: { gt: 0 } },
    orderBy: { date: "desc" },
    take: 500,
  });

  let created = 0;

  for (const conv of conversions) {
    // Check if attribution already exists
    const existing = await prisma.revenueAttribution.findFirst({
      where: {
        brandId,
        channel: conv.channel,
        date: conv.date,
        conversionType: conv.type,
        landingPage: conv.landingPage,
        attributionModel: model,
      },
    });

    if (existing) continue;

    await prisma.revenueAttribution.create({
      data: {
        brandId,
        attributionModel: model,
        channel: conv.channel,
        landingPage: conv.landingPage,
        conversionType: conv.type,
        revenue: conv.value,
        creditPct: 100,
        date: conv.date,
      },
    });
    created++;
  }

  return { created, total: conversions.length };
}

/**
 * Get the closed-loop journey summary.
 * Maps: source → page → conversion → CRM → revenue
 */
export async function getClosedLoopSummary(brandId: string, range: DateRange = "30d") {
  const { start, end } = getDateRange(range);

  // Get deals with their linked conversions
  const deals = await prisma.crmDeal.findMany({
    where: { brandId, createdAt: { gte: start, lte: end } },
    include: { conversion: true },
  });

  const journeys = deals
    .filter((d) => d.conversion)
    .map((d) => ({
      source: d.conversion!.source || d.conversion!.channel,
      page: d.conversion!.landingPage || "unknown",
      conversionType: d.conversion!.type,
      dealName: d.dealName,
      dealValue: d.value,
      dealStatus: d.status,
      closeDate: d.closeDate,
    }));

  // Revenue by journey source
  const bySource: Record<string, { count: number; revenue: number; won: number }> = {};
  for (const j of journeys) {
    const key = j.source || "direct";
    if (!bySource[key]) bySource[key] = { count: 0, revenue: 0, won: 0 };
    bySource[key].count++;
    bySource[key].revenue += j.dealValue;
    if (j.dealStatus === "won") bySource[key].won++;
  }

  return {
    totalJourneys: journeys.length,
    totalRevenue: Math.round(journeys.reduce((s, j) => s + j.dealValue, 0)),
    linkedDeals: deals.filter((d) => d.conversionId).length,
    unlinkedDeals: deals.filter((d) => !d.conversionId).length,
    bySource: Object.entries(bySource).map(([source, data]) => ({ source, ...data })).sort((a, b) => b.revenue - a.revenue),
    journeys: journeys.slice(0, 20),
  };
}

/**
 * Get attribution breakdown comparing all three models side by side.
 * Returns per-channel revenue for first_touch, last_touch, and assisted.
 */
export async function getAttributionBreakdown(brandId: string, range: DateRange = "30d") {
  const { start, end } = getDateRange(range);

  const all = await prisma.revenueAttribution.findMany({
    where: { brandId, date: { gte: start, lte: end } },
    orderBy: { date: "desc" },
  });

  // Group by model
  const firstTouch = all.filter((r) => r.attributionModel === "first_touch");
  const lastTouch = all.filter((r) => r.attributionModel === "last_touch");
  const assisted = all.filter((r) => r.attributionModel === "assisted");

  // Get all unique channels
  const channels = [...new Set(all.map((r) => r.channel))];

  // Per-channel breakdown across models
  const byChannel = channels.map((channel) => {
    const ft = sumRevenue(firstTouch.filter((r) => r.channel === channel));
    const lt = sumRevenue(lastTouch.filter((r) => r.channel === channel));
    const as = sumRevenue(assisted.filter((r) => r.channel === channel));

    return {
      channel,
      firstTouch: { revenue: ft.revenue, count: ft.count },
      lastTouch: { revenue: lt.revenue, count: lt.count },
      assisted: { revenue: as.revenue, count: as.count },
      totalRevenue: ft.revenue + lt.revenue + as.revenue,
    };
  }).sort((a, b) => b.totalRevenue - a.totalRevenue);

  // Model totals
  const totals = {
    firstTouch: { revenue: sumRevenue(firstTouch).revenue, count: firstTouch.length },
    lastTouch: { revenue: sumRevenue(lastTouch).revenue, count: lastTouch.length },
    assisted: { revenue: sumRevenue(assisted).revenue, count: assisted.length },
  };

  // Direct vs assisted revenue (last_touch = direct, assisted = multi-touch)
  const directRevenue = totals.lastTouch.revenue;
  const assistedRevenue = totals.assisted.revenue;
  const directPct = directRevenue + assistedRevenue > 0
    ? Math.round((directRevenue / (directRevenue + assistedRevenue)) * 100)
    : 0;

  return {
    byChannel,
    totals,
    directRevenue,
    assistedRevenue,
    directPct,
    assistedPct: 100 - directPct,
    channelCount: channels.length,
    recordCount: all.length,
  };
}

function sumRevenue(items: Array<{ revenue: number; creditPct: number }>) {
  return {
    revenue: Math.round(items.reduce((s, r) => s + r.revenue * (r.creditPct / 100), 0)),
    count: items.length,
  };
}

// Helper
function groupAndSum(items: Array<{ revenue: number; creditPct: number; [key: string]: unknown }>, key: string) {
  const result: Record<string, { revenue: number; count: number }> = {};
  for (const item of items) {
    const k = String(item[key] || "unknown");
    if (!result[k]) result[k] = { revenue: 0, count: 0 };
    result[k].revenue += Math.round(item.revenue * (item.creditPct / 100));
    result[k].count++;
  }
  return result;
}
