import { db } from "@/db";
import { project_offers, offer_micros, offer_macros, projects } from "@/db/schema";
import { eq, sql, desc } from "drizzle-orm";

export type ForecastMonth = {
  year: number;
  month: number;    // 1-12
  label: string;   // "giu 2026"
  total: number;
};

export type OffersSoldRow = {
  offer_name: string;       // offer_macros.internal_name
  tier_letter: string | null;
  count: number;
};

export type OffersSoldBreakdown = {
  rows: OffersSoldRow[];
  total: number;
};

// Quante offerte sono state vendute (assegnate a un progetto), per offerta + tier.
export async function getOffersSoldBreakdown(): Promise<OffersSoldBreakdown> {
  const rows = await db
    .select({
      offer_name: offer_macros.internal_name,
      tier_letter: offer_micros.tier_letter,
      count: sql<number>`count(*)::int`,
    })
    .from(project_offers)
    .innerJoin(offer_micros, eq(project_offers.micro_id, offer_micros.id))
    .innerJoin(offer_macros, eq(offer_micros.macro_id, offer_macros.id))
    .groupBy(offer_macros.internal_name, offer_micros.tier_letter)
    .orderBy(desc(sql`count(*)`));

  const total = rows.reduce((sum, r) => sum + Number(r.count), 0);
  return {
    rows: rows.map((r) => ({
      offer_name: r.offer_name,
      tier_letter: r.tier_letter,
      count: Number(r.count),
    })),
    total,
  };
}

export async function getRevenueForecast12Months(): Promise<ForecastMonth[]> {
  // Active offers only (non-archived projects). offer_type drives the math:
  //  - retainer:   accepted_total è il CANONE MENSILE → ogni mese coperto riceve l'intero importo
  //  - una_tantum: accepted_total è il prezzo TOTALE → spalmato su duration_months
  const offers = await db
    .select({
      start_date: project_offers.start_date,
      duration_months: offer_micros.duration_months,
      accepted_total: project_offers.accepted_total,
      offer_type: offer_macros.offer_type,
    })
    .from(project_offers)
    .innerJoin(offer_micros, eq(project_offers.micro_id, offer_micros.id))
    .innerJoin(offer_macros, eq(offer_micros.macro_id, offer_macros.id))
    .innerJoin(projects, eq(project_offers.project_id, projects.id))
    .where(eq(projects.archived, false));

  // Build 12-month bucket array starting from current month
  const now = new Date();
  const buckets: ForecastMonth[] = Array.from({ length: 12 }, (_, i) => {
    const d = new Date(now.getFullYear(), now.getMonth() + i, 1);
    return {
      year: d.getFullYear(),
      month: d.getMonth() + 1,
      label: d.toLocaleDateString("it-IT", { month: "short", year: "numeric" }),
      total: 0,
    };
  });

  for (const offer of offers) {
    if (!offer.accepted_total) continue;
    const total = parseFloat(String(offer.accepted_total));
    if (isNaN(total) || total <= 0) continue;

    const start = new Date(offer.start_date);
    const startMonthKey = start.getFullYear() * 12 + start.getMonth();

    if (offer.offer_type === "retainer") {
      // Canone ricorrente: contribuisce ad OGNI mese dell'orizzonte da start in poi,
      // senza limite di duration_months (un retainer è continuativo).
      for (const b of buckets) {
        const bucketMonthKey = b.year * 12 + (b.month - 1);
        if (bucketMonthKey >= startMonthKey) b.total += total;
      }
    } else {
      // Una tantum: prezzo totale ripartito su duration_months a partire da start.
      const months = offer.duration_months > 0 ? offer.duration_months : 1;
      const perMonth = total / months;
      for (let m = 0; m < months; m++) {
        const offerMonth = new Date(start.getFullYear(), start.getMonth() + m, 1);
        const bucket = buckets.find(
          (b) => b.year === offerMonth.getFullYear() && b.month === offerMonth.getMonth() + 1
        );
        if (bucket) bucket.total += perMonth;
      }
    }
  }

  // Round totals to 2 decimal places
  buckets.forEach((b) => { b.total = Math.round(b.total * 100) / 100; });

  return buckets;
}
