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

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

/** Monthly fare collection sheet (?month=YYYY-MM). */
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 monthParam = url.searchParams.get("month");
  const month = monthParam && /^\d{4}-\d{2}$/.test(monthParam) ? monthParam : currentMonth();

  const [members, payments] = await Promise.all([
    prisma.transportMember.findMany({
      where: { institutionId: session.institutionId, status: "ACTIVE" },
      include: {
        student: { select: { roll: true, name: true } },
        route: { select: { name: true } },
        stop: { select: { name: true } },
      },
      orderBy: { id: "asc" },
    }),
    prisma.transportPayment.findMany({
      where: { institutionId: session.institutionId, month },
    }),
  ]);

  const paidByMember = new Map(payments.map((p) => [p.memberId, p]));
  const expected = members.reduce((sum, m) => sum + Number(m.monthlyFare), 0);
  const paid = payments.reduce((sum, p) => sum + Number(p.amount), 0);

  return NextResponse.json({
    month,
    rows: members.map((m) => ({
      memberId: m.id,
      roll: m.student.roll,
      studentName: m.student.name,
      routeName: m.route.name,
      stopName: m.stop?.name ?? null,
      fare: Number(m.monthlyFare),
      paid: paidByMember.has(m.id),
      paidAmount: paidByMember.has(m.id) ? Number(paidByMember.get(m.id)!.amount) : 0,
      method: paidByMember.get(m.id)?.method ?? null,
      trxId: paidByMember.get(m.id)?.trxId ?? null,
      paidAt: paidByMember.get(m.id)?.paidAt ?? null,
    })),
    summary: { expected, paid, due: Math.max(0, expected - paid), paidCount: payments.length },
  });
}

/** Collect a member's monthly fare: { memberId, month, amount?, method, trxId?, note? }.
    Digital payments (bKash/Nagad/Rocket/Card/Bank Transfer) MUST carry a
    transaction / reference id — cash needs none. */
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 memberId = Number(body.memberId);
    const month = String(body.month ?? "");
    if (!memberId || !/^\d{4}-\d{2}$/.test(month)) {
      return NextResponse.json({ error: "Missing fields" }, { status: 400 });
    }

    const member = await prisma.transportMember.findFirst({
      where: { id: memberId, institutionId: session.institutionId, status: "ACTIVE" },
    });
    if (!member) return NextResponse.json({ error: "Member not found" }, { status: 404 });

    const amount =
      body.amount !== undefined && Number(body.amount) > 0
        ? Number(body.amount)
        : Number(member.monthlyFare);
    if (!(amount > 0)) return NextResponse.json({ error: "Invalid amount" }, { status: 400 });

    const existing = await prisma.transportPayment.findUnique({
      where: { memberId_month: { memberId, month } },
    });
    if (existing) return NextResponse.json({ error: "ALREADY_PAID" }, { status: 409 });

    const method = PAYMENT_METHODS.includes(body.method as never) ? body.method : "CASH";
    const trxId = String(body.trxId ?? "").trim() || null;
    if (method !== "CASH" && !trxId) {
      return NextResponse.json({ error: "TRX_REQUIRED" }, { status: 400 });
    }

    const payment = await prisma.transportPayment.create({
      data: {
        institutionId: session.institutionId,
        memberId,
        month,
        amount,
        method,
        trxId,
        note: String(body.note ?? "").trim() || null,
        paidById: session.userId,
      },
    });
    return NextResponse.json({ payment });
  } catch {
    return NextResponse.json({ error: "Could not record payment" }, { status: 500 });
  }
}
