import { connectDB } from "@/lib/db";
import { Order } from "@/models/Order";
import { Client } from "@/models/Client";
import { PriceProposal } from "@/models/PriceProposal";
import { Expense } from "@/models/Expense";
import { Income } from "@/models/Income";
import { getPayableAmount, getTotalOrderDiscount } from "@/lib/discounts";
import { getSettings } from "@/lib/settings";

function monthKey(d: Date) {
  return new Date(d).toISOString().slice(0, 7);
}

// Bewusst ein kleiner Ausschnitt aus admin/statistics/page.tsx (956 Zeilen,
// 4 Tabs mit Diagrammen) — nur die reinen Kennzahlen ohne Chart-Komponenten
// (Umsatz, offene Zahlungen, Gewinn/Steuerrücklage, Monatstrend als Zahlen
// statt Linien-Diagramm). Alles andere (Funnel, Bewertungen, Marketing,
// Diagramme) bleibt vorerst der Web-Ansicht vorbehalten.
export async function getRevenueStats() {
  await connectDB();
  const [settings, orders, clients, expenses, priceProposals, manualIncome] = await Promise.all([
    getSettings(),
    Order.find({}).lean(),
    Client.find({}).lean(),
    Expense.find({}).lean(),
    PriceProposal.find({ status: "accepted" }).lean(),
    Income.find({}).lean(),
  ]);
  const clientById = new Map(clients.map((c) => [String(c._id), c]));
  const realClientsCount = clients.filter((c) => c.role === "client").length;
  const ordersById = new Map(orders.map((o) => [String(o._id), o]));

  const acceptedProposals = priceProposals.filter((p) => {
    const o = ordersById.get(String(p.orderId));
    return o && !o.rejected;
  });
  const payableFor = (p: { orderId: unknown; amount: number }) => {
    const o = ordersById.get(String(p.orderId));
    return getPayableAmount(p.amount, o ? getTotalOrderDiscount(o) : 0);
  };

  const amounts = acceptedProposals.map((p) => payableFor(p));
  const totalAgreed = amounts.reduce((a, b) => a + b, 0);
  const acceptedByOrderId = new Map(acceptedProposals.map((p) => [String(p.orderId), p]));

  const paidOrdersWithPrice = orders.filter((o) => o.paid && !o.rejected && acceptedByOrderId.has(String(o._id)));
  const paidAmounts = paidOrdersWithPrice.map((o) => payableFor(acceptedByOrderId.get(String(o._id))!));
  const totalRevenue = paidAmounts.reduce((a, b) => a + b, 0);
  const avgRevenue = paidAmounts.length ? totalRevenue / paidAmounts.length : 0;

  const revenueByMonth = new Map<string, number>();
  for (const o of paidOrdersWithPrice) {
    const amount = payableFor(acceptedByOrderId.get(String(o._id))!);
    const key = monthKey(o.paidAt || o.createdAt);
    revenueByMonth.set(key, (revenueByMonth.get(key) ?? 0) + amount);
  }
  const revenueMonths = [...revenueByMonth.entries()].sort(([a], [b]) => a.localeCompare(b));

  const openPaymentOrders = orders.filter(
    (o) => o.compensationType === "paid" && !o.paid && !o.rejected && !o.archived && acceptedByOrderId.has(String(o._id))
  );
  const openPaymentAmount = openPaymentOrders.reduce((sum, o) => sum + payableFor(acceptedByOrderId.get(String(o._id))!), 0);

  const manualIncomeTotal = manualIncome.reduce((sum, i) => sum + i.amount, 0);
  const combinedIncomeTotal = totalRevenue + manualIncomeTotal;
  const combinedIncomeByMonth = new Map(revenueByMonth);
  for (const i of manualIncome) {
    const key = monthKey(i.date);
    combinedIncomeByMonth.set(key, (combinedIncomeByMonth.get(key) ?? 0) + i.amount);
  }

  const totalExpenses = expenses.reduce((sum, e) => sum + e.amount, 0);
  const expensesByMonth = new Map<string, number>();
  for (const e of expenses) {
    const key = monthKey(e.date);
    expensesByMonth.set(key, (expensesByMonth.get(key) ?? 0) + e.amount);
  }
  const profitMonths = [...new Set([...combinedIncomeByMonth.keys(), ...expensesByMonth.keys()])]
    .sort((a, b) => a.localeCompare(b))
    .map((month) => {
      const income = combinedIncomeByMonth.get(month) ?? 0;
      const expense = expensesByMonth.get(month) ?? 0;
      return { month, income, expense, profit: income - expense };
    });

  const profit = combinedIncomeTotal - totalExpenses;
  const taxReservePercentage = settings.taxReserveSettings.percentage;
  const taxReserveAmount = Math.max(0, profit) * (taxReservePercentage / 100);

  return {
    ordersCount: orders.length,
    clientsCount: realClientsCount,
    totalRevenue,
    openPaymentAmount,
    totalAgreed,
    avgRevenue,
    revenueMonths,
    profit,
    taxReservePercentage,
    taxReserveAmount,
    profitMonths,
    openPaymentOrders: openPaymentOrders.map((o) => ({
      _id: String(o._id),
      characterOrConcept: o.characterOrConcept,
      clientName: clientById.get(String(o.clientId))?.name || "Unbekannt",
      amount: payableFor(acceptedByOrderId.get(String(o._id))!),
    })),
  };
}
