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

/** Fees dashboard: totals, per-head breakdown, monthly collection, due list. */
export async function GET() {
  const session = await requireRole("INSTITUTION_ADMIN");
  if (!session || !session.institutionId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const [schedules, collections, studentCount] = await Promise.all([
    prisma.feeSchedule.findMany({
      where: { institutionId: session.institutionId },
      include: {
        feeHead: { select: { name: true, nameBn: true, type: true } },
        student: { select: { id: true, roll: true, name: true, classItemId: true } },
        payments: { select: { amount: true } },
      },
    }),
    prisma.feeCollection.findMany({
      where: { institutionId: session.institutionId },
      select: { amount: true, paidAt: true },
    }),
    prisma.student.count({ where: { institutionId: session.institutionId, status: "ACTIVE" } }),
  ]);

  let assigned = 0;
  let collectedOfSchedules = 0;
  const headMap = new Map<string, { name: string; nameBn: string | null; type: string; assigned: number; collected: number }>();
  const dueRows: {
    scheduleId: number;
    title: string;
    headName: string;
    studentId: number;
    roll: string;
    name: string;
    amount: number;
    paid: number;
    due: number;
    dueDate: Date;
    month: string | null;
  }[] = [];

  for (const fs of schedules) {
    const total = Number(fs.amount);
    const paid = fs.payments.reduce((s, p) => s + Number(p.amount), 0);
    const due = Math.max(0, total - paid);
    assigned += total;
    collectedOfSchedules += Math.min(paid, total);

    const key = fs.feeHead.name;
    const head = headMap.get(key) ?? {
      name: fs.feeHead.name,
      nameBn: fs.feeHead.nameBn,
      type: fs.feeHead.type,
      assigned: 0,
      collected: 0,
    };
    head.assigned += total;
    head.collected += Math.min(paid, total);
    headMap.set(key, head);

    if (due > 0 && fs.student) {
      dueRows.push({
        scheduleId: fs.id,
        title: fs.title,
        headName: fs.feeHead.name,
        studentId: fs.student.id,
        roll: fs.student.roll,
        name: fs.student.name,
        amount: total,
        paid,
        due,
        dueDate: fs.dueDate,
        month: fs.month,
      });
    }
  }

  // Monthly collections for last 6 months
  const monthly: { key: string; label: string; total: number }[] = [];
  const now = new Date();
  for (let i = 5; i >= 0; i--) {
    const d = new Date(now.getFullYear(), now.getMonth() - i, 1);
    const total = collections
      .filter((c) => {
        const cd = new Date(c.paidAt);
        return cd.getFullYear() === d.getFullYear() && cd.getMonth() === d.getMonth();
      })
      .reduce((s, c) => s + Number(c.amount), 0);
    monthly.push({ key: `${d.getFullYear()}-${d.getMonth()}`, label: d.toLocaleString("en", { month: "short" }), total });
  }

  dueRows.sort((a, b) => b.due - a.due);

  return NextResponse.json({
    totals: {
      assigned,
      collected: collections.reduce((s, c) => s + Number(c.amount), 0),
      scheduleCollected: collectedOfSchedules,
      due: assigned - collectedOfSchedules,
      students: studentCount,
      assignments: schedules.length,
      dueCount: dueRows.length,
    },
    heads: Array.from(headMap.values()),
    dueRows: dueRows.slice(0, 50),
    monthly,
  });
}
