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

/** Decide an online payment claim. approve → posts a regular FeeCollection
    (same invoice numbering / fields the office records manually) and links it
    to the claim; reject → records the decision note. */
export async function PATCH(req: Request, { params }: { params: Promise<{ id: string }> }) {
  const session = await requireRole("INSTITUTION_ADMIN");
  if (!session || !session.institutionId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const { id } = await params;
  const claimId = Number(id);
  if (!Number.isInteger(claimId) || claimId <= 0) {
    return NextResponse.json({ error: "BAD_CLAIM" }, { status: 400 });
  }

  try {
    const body = await req.json();
    const action = String(body.action ?? "");
    const decisionNote = String(body.note ?? "").trim().slice(0, 300) || null;
    if (action !== "approve" && action !== "reject") {
      return NextResponse.json({ error: "BAD_ACTION" }, { status: 400 });
    }

    const claim = await prisma.feePaymentClaim.findFirst({
      where: { id: claimId, institutionId: session.institutionId },
    });
    if (!claim) return NextResponse.json({ error: "Not found" }, { status: 404 });
    if (claim.status !== "PENDING") {
      return NextResponse.json({ error: "ALREADY_DECIDED" }, { status: 409 });
    }

    if (action === "reject") {
      const updated = await prisma.feePaymentClaim.update({
        where: { id: claim.id },
        data: {
          status: "REJECTED",
          decisionNote,
          decidedById: session.userId,
          decidedAt: new Date(),
        },
      });
      return NextResponse.json({ claim: updated });
    }

    // approve — re-check the fee item's remaining due inside the transaction
    const collection = await prisma.$transaction(async (tx) => {
      if (claim.feeScheduleId) {
        const schedule = await tx.feeSchedule.findUnique({
          where: { id: claim.feeScheduleId },
          include: { payments: { select: { amount: true } } },
        });
        if (schedule) {
          const paid = schedule.payments.reduce((s, p) => s + Number(p.amount), 0);
          if (Number(claim.amount) > Number(schedule.amount) - paid) {
            return null; // overpay guard — the caller surfaces CLAIM_STALE
          }
        }
      }
      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: claim.studentId,
          feeScheduleId: claim.feeScheduleId,
          amount: claim.amount,
          method: claim.method,
          details: claim.details ?? undefined,
          note: claim.note ?? null,
          collectedById: session.userId,
        },
      });
    });

    if (!collection) {
      return NextResponse.json({ error: "CLAIM_STALE" }, { status: 409 });
    }

    const updated = await prisma.feePaymentClaim.update({
      where: { id: claim.id },
      data: {
        status: "APPROVED",
        decisionNote,
        decidedById: session.userId,
        decidedAt: new Date(),
        collectionId: collection.id,
      },
      include: { collection: { select: { invoiceNo: true } } },
    });

    return NextResponse.json({ claim: updated });
  } catch {
    return NextResponse.json({ error: "Could not decide claim" }, { status: 500 });
  }
}
