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

export async function GET() {
  const session = await requireRole("INSTITUTION_ADMIN");
  if (!session || !session.institutionId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const collections = await prisma.feeCollection.findMany({
    where: { institutionId: session.institutionId },
    orderBy: { paidAt: "desc" },
    take: 100,
    include: {
      student: { select: { roll: true, name: true } },
      feeSchedule: { select: { title: true, feeHead: { select: { name: true } } } },
    },
  });

  return NextResponse.json({ collections });
}

/** Record a fee collection against a student (optionally a specific schedule). */
export async function POST(req: Request) {
  const session = await requireRole("INSTITUTION_ADMIN");
  if (!session || !session.institutionId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  try {
    const body = await req.json();
    const studentId = Number(body.studentId);
    const feeScheduleId = body.feeScheduleId ? Number(body.feeScheduleId) : null;
    const amount = Number(body.amount);
    const method = String(body.method ?? "CASH");
    const note = String(body.note ?? "").trim() || null;

    // method-specific transaction details (TrxID / bank+cheque / card …)
    const details: Record<string, string> = {};
    if (body.details && typeof body.details === "object") {
      for (const [key, value] of Object.entries(body.details as Record<string, unknown>)) {
        const k = key.replace(/[^a-zA-Z0-9]/g, "").slice(0, 20);
        const v = String(value ?? "").trim().slice(0, 60);
        if (k && v) details[k] = v;
      }
    }

    if (!Number.isFinite(amount) || amount <= 0) {
      return NextResponse.json({ error: "INVALID_AMOUNT" }, { status: 400 });
    }
    if (!PAYMENT_METHODS.includes(method as never)) {
      return NextResponse.json({ error: "Invalid method" }, { status: 400 });
    }

    const student = await prisma.student.findFirst({
      where: { id: studentId, institutionId: session.institutionId },
    });
    if (!student) return NextResponse.json({ error: "Student not found" }, { status: 404 });

    let schedule = null;
    if (feeScheduleId) {
      schedule = await prisma.feeSchedule.findFirst({
        where: { id: feeScheduleId, institutionId: session.institutionId, studentId },
        include: { payments: { select: { amount: true } } },
      });
      if (!schedule) return NextResponse.json({ error: "Schedule not found" }, { status: 404 });
      const paid = schedule.payments.reduce((s, p) => s + Number(p.amount), 0);
      if (amount > Number(schedule.amount) - paid) {
        return NextResponse.json({ error: "AMOUNT_EXCEEDS" }, { status: 400 });
      }
    }

    const collection = await prisma.$transaction(async (tx) => {
      const count = await tx.feeCollection.count();
      const invoiceNo = `FEE-${String(count + 1).padStart(6, "0")}`;
      return tx.feeCollection.create({
        data: {
          invoiceNo,
          institutionId: session.institutionId!,
          studentId,
          feeScheduleId,
          amount,
          method: method as never,
          details: Object.keys(details).length > 0 ? details : undefined,
          note,
          collectedById: session.userId,
        },
        include: {
          student: { select: { roll: true, name: true } },
          feeSchedule: { select: { title: true, feeHead: { select: { name: true } } } },
        },
      });
    });

    return NextResponse.json({ collection });
  } catch {
    return NextResponse.json({ error: "Could not record collection" }, { status: 500 });
  }
}
