import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { requireRole } from "@/lib/auth";
import { PAYMENT_METHODS } from "@/lib/constants";
import { institutionAdmin, sendCentralMail } from "@/lib/central-mail";
import { appBaseUrl, paymentReceivedEmail } from "@/lib/email-templates";

const METHOD_LABELS: Record<string, string> = {
  BKASH: "bKash (Mobile Banking)",
  NAGAD: "Nagad (Mobile Banking)",
  ROCKET: "Rocket (Mobile Banking)",
  CARD: "Card Payment",
  BANK_TRANSFER: "Bank Transfer",
  CASH: "Cash",
};

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

  const [payments, subscriptions] = await Promise.all([
    prisma.payment.findMany({
      orderBy: { paidAt: "desc" },
      include: {
        institution: { select: { name: true } },
        subscription: {
          include: { packagePlan: { select: { name: true } } },
        },
        collectedBy: { select: { name: true } },
      },
    }),
    prisma.subscription.findMany({
      where: { status: "ACTIVE" },
      include: {
        institution: { select: { id: true, name: true, type: true } },
        packagePlan: { select: { name: true } },
        payments: { select: { amount: true } },
      },
      orderBy: { createdAt: "desc" },
    }),
  ]);

  // Attach paid/due amounts to each subscription
  const dueSubscriptions = subscriptions.map((s) => {
    const paid = s.payments.reduce((sum, p) => sum + Number(p.amount), 0);
    const total = Number(s.totalAmount);
    return {
      id: s.id,
      institution: s.institution,
      packagePlan: s.packagePlan,
      startDate: s.startDate,
      endDate: s.endDate,
      totalAmount: total,
      paid,
      due: Math.max(0, total - paid),
    };
  });

  return NextResponse.json({ payments, dueSubscriptions });
}

export async function POST(req: Request) {
  const session = await requireRole("SUPER_ADMIN");
  if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });

  try {
    const body = await req.json();
    const subscriptionId = Number(body.subscriptionId);
    const amount = Number(body.amount);
    const method = String(body.method ?? "");
    const transactionRef = String(body.transactionRef ?? "").trim() || null;
    const note = String(body.note ?? "").trim() || null;

    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 subscription = await prisma.subscription.findUnique({
      where: { id: subscriptionId },
      include: { payments: { select: { amount: true } } },
    });
    if (!subscription) {
      return NextResponse.json({ error: "Subscription not found" }, { status: 404 });
    }

    const paid = subscription.payments.reduce((sum, p) => sum + Number(p.amount), 0);
    const remaining = Number(subscription.totalAmount) - paid;
    if (amount > remaining) {
      return NextResponse.json({ error: "AMOUNT_EXCEEDS" }, { status: 400 });
    }

    // Generate sequential invoice number inside a transaction
    const payment = await prisma.$transaction(async (tx) => {
      const count = await tx.payment.count();
      const invoiceNo = `INV-${String(count + 1).padStart(6, "0")}`;
      return tx.payment.create({
        data: {
          invoiceNo,
          subscriptionId,
          institutionId: subscription.institutionId,
          amount,
          method: method as never,
          transactionRef,
          note,
          collectedById: session.userId,
          paidAt: new Date(),
        },
        include: {
          institution: { select: { name: true } },
          collectedBy: { select: { name: true } },
        },
      });
    });

    // Thank-you receipt to the institution admin — never blocks the payment
    try {
      const admin = await institutionAdmin(subscription.institutionId);
      if (admin) {
        const full = await prisma.subscription.findUnique({
          where: { id: subscriptionId },
          select: {
            startDate: true,
            endDate: true,
            totalAmount: true,
            packagePlan: { select: { name: true } },
            payments: { select: { amount: true } },
          },
        });
        if (full) {
          const paidToDate = full.payments.reduce((sum, p) => sum + Number(p.amount), 0);
          const due = Math.max(0, Number(full.totalAmount) - paidToDate);
          const tpl = paymentReceivedEmail({
            toName: admin.name,
            institutionName: payment.institution.name,
            invoiceNo: payment.invoiceNo,
            packageName: full.packagePlan?.name ?? "—",
            amount,
            methodLabel: METHOD_LABELS[method] ?? method,
            transactionRef,
            paidAt: payment.paidAt,
            periodStart: full.startDate,
            periodEnd: full.endDate,
            totalAmount: Number(full.totalAmount),
            paidToDate,
            dueAmount: due,
            billingUrl: `${appBaseUrl()}/portal/billing`,
          });
          await sendCentralMail({
            to: admin.email,
            subject: tpl.subject,
            html: tpl.html,
            text: tpl.text,
            institutionId: subscription.institutionId,
          });
        }
      }
    } catch (err) {
      console.error("payment-receipt-mail-failed", err);
    }

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