import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { requireRole } from "@/lib/auth";

/** Income & Expense statement: head-wise breakdown + monthly trend for a date range. */
export async function GET(req: Request) {
  const session = await requireRole("INSTITUTION_ADMIN");
  if (!session || !session.institutionId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const url = new URL(req.url);
  const fromParam = url.searchParams.get("from");
  const toParam = url.searchParams.get("to");
  const isoDate = /^\d{4}-\d{2}-\d{2}$/;

  // Default range: last 12 months → today
  const today = new Date();
  const defaultFrom = new Date(today.getFullYear(), today.getMonth() - 11, 1);
  const fmt = (d: Date) =>
    `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;

  const from = fromParam && isoDate.test(fromParam) ? fromParam : fmt(defaultFrom);
  const to = toParam && isoDate.test(toParam) ? toParam : fmt(today);

  const [entries, heads] = await Promise.all([
    prisma.accountEntry.findMany({
      where: {
        institutionId: session.institutionId,
        date: { gte: new Date(`${from}T00:00:00`), lte: new Date(`${to}T23:59:59`) },
      },
      select: { type: true, amount: true, date: true, headId: true, head: { select: { name: true, nameBn: true } } },
    }),
    prisma.accountHead.findMany({
      where: { institutionId: session.institutionId },
      select: { id: true, name: true, nameBn: true, type: true },
      orderBy: { name: "asc" },
    }),
  ]);

  let incomeTotal = 0;
  let expenseTotal = 0;
  const incomeByHead = new Map<number, { name: string; nameBn: string | null; total: number; count: number }>();
  const expenseByHead = new Map<number, { name: string; nameBn: string | null; total: number; count: number }>();
  const monthMap = new Map<string, { income: number; expense: number }>();

  for (const e of entries) {
    const amount = Number(e.amount);
    const target = e.type === "INCOME" ? incomeByHead : expenseByHead;
    const row = target.get(e.headId) ?? { name: e.head.name, nameBn: e.head.nameBn, total: 0, count: 0 };
    row.total += amount;
    row.count += 1;
    target.set(e.headId, row);

    if (e.type === "INCOME") incomeTotal += amount;
    else expenseTotal += amount;

    const d = new Date(e.date);
    const key = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`;
    const month = monthMap.get(key) ?? { income: 0, expense: 0 };
    if (e.type === "INCOME") month.income += amount;
    else month.expense += amount;
    monthMap.set(key, month);
  }

  // Fill months that have heads but no entries so the trend/table is continuous
  const monthly: { key: string; label: string; income: number; expense: number }[] = [];
  const start = new Date(`${from}T00:00:00`);
  const end = new Date(`${to}T00:00:00`);
  const cursor = new Date(start.getFullYear(), start.getMonth(), 1);
  const endMonth = new Date(end.getFullYear(), end.getMonth(), 1);
  while (cursor <= endMonth && monthly.length < 24) {
    const key = `${cursor.getFullYear()}-${String(cursor.getMonth() + 1).padStart(2, "0")}`;
    const m = monthMap.get(key) ?? { income: 0, expense: 0 };
    monthly.push({
      key,
      label: cursor.toLocaleString("en", { month: "short", year: "2-digit" }),
      income: m.income,
      expense: m.expense,
    });
    cursor.setMonth(cursor.getMonth() + 1);
  }

  return NextResponse.json({
    range: { from, to },
    totals: {
      income: incomeTotal,
      expense: expenseTotal,
      balance: incomeTotal - expenseTotal,
      count: entries.length,
    },
    incomeByHead: Array.from(incomeByHead.values()).sort((a, b) => b.total - a.total),
    expenseByHead: Array.from(expenseByHead.values()).sort((a, b) => b.total - a.total),
    headsCount: heads.length,
    monthly,
  });
}
