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

type Params = { params: Promise<{ id: string }> };

/** Delete an admission application (with its message thread). Applications
 *  that were approved and already created a student are kept — remove the
 *  student record from the Students page instead. */
export async function DELETE(_req: Request, { params }: Params) {
  const session = await requireRole("INSTITUTION_ADMIN");
  if (!session || !session.institutionId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const { id } = await params;
  try {
    const admission = await prisma.admission.findFirst({
      where: { id: Number(id), institutionId: session.institutionId },
      select: { id: true, student: { select: { id: true } } },
    });
    if (!admission) return NextResponse.json({ error: "Not found" }, { status: 404 });
    if (admission.student) {
      return NextResponse.json({ error: "LINKED_STUDENT" }, { status: 409 });
    }
    await prisma.admission.delete({ where: { id: admission.id } });
    return NextResponse.json({ ok: true });
  } catch {
    return NextResponse.json({ error: "Could not delete application" }, { status: 500 });
  }
}

/** Decide an application (approve enrolls a student / reject) or manage its
 *  application fee: { action: "fee", feeAction: "mark-paid" | "waive" | "reopen" }. */
export async function PATCH(req: Request, { params }: Params) {
  const session = await requireRole("INSTITUTION_ADMIN");
  if (!session || !session.institutionId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const { id } = await params;
  const admissionId = Number(id);
  const body = await req.json().catch(() => ({}));
  const action = String(body.action ?? "");

  if (!["approve", "reject", "fee"].includes(action)) {
    return NextResponse.json({ error: "Invalid action" }, { status: 400 });
  }

  const admission = await prisma.admission.findFirst({
    where: { id: admissionId, institutionId: session.institutionId },
    include: { student: true },
  });
  if (!admission) return NextResponse.json({ error: "Not found" }, { status: 404 });

  /* ---------- application fee management (works for any application status) ---------- */
  if (action === "fee") {
    if (Number(admission.feeAmount) <= 0) {
      return NextResponse.json({ error: "NO_FEE" }, { status: 400 });
    }
    const feeAction = String(body.feeAction ?? "");

    if (feeAction === "waive") {
      const updated = await prisma.admission.update({
        where: { id: admissionId },
        data: {
          feeStatus: "WAIVED",
          feeMethod: null,
          feeDetails: Prisma.DbNull,
          feePaidAt: null,
          feeRecordedById: session.userId,
        },
      });
      return NextResponse.json({ admission: updated });
    }

    if (feeAction === "reopen") {
      const updated = await prisma.admission.update({
        where: { id: admissionId },
        data: {
          feeStatus: "DUE",
          feeMethod: null,
          feeDetails: Prisma.DbNull,
          feePaidAt: null,
          feeRecordedById: session.userId,
        },
      });
      return NextResponse.json({ admission: updated });
    }

    if (feeAction === "mark-paid") {
      const method = String(body.method ?? "CASH");
      if (!PAYMENT_METHODS.includes(method as never)) {
        return NextResponse.json({ error: "Invalid method" }, { status: 400 });
      }
      // 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;
        }
      }
      const updated = await prisma.admission.update({
        where: { id: admissionId },
        data: {
          feeStatus: "PAID",
          feeMethod: method as never,
          feeDetails: Object.keys(details).length > 0 ? details : undefined,
          feePaidAt: new Date(),
          feeRecordedById: session.userId,
        },
      });
      return NextResponse.json({ admission: updated });
    }

    return NextResponse.json({ error: "Invalid fee action" }, { status: 400 });
  }

  if (admission.status !== "PENDING") {
    return NextResponse.json({ error: "Already decided" }, { status: 409 });
  }

  if (action === "reject") {
    const updated = await prisma.admission.update({
      where: { id: admissionId },
      data: { status: "REJECTED", decidedAt: new Date() },
    });
    return NextResponse.json({ admission: updated });
  }

  // Approve → create the student. A custom roll may be supplied; otherwise
  // the next sequential roll for this institution is auto-assigned.
  try {
    // subscription range control: an active slab subscription caps the
    // number of ACTIVE students the institution may have
    const activeRangeSub = await prisma.subscription.findFirst({
      where: { institutionId: session.institutionId!, status: "ACTIVE", pricingTierId: { not: null } },
      orderBy: { endDate: "desc" },
      include: { pricingTier: true },
    });
    if (activeRangeSub?.pricingTier?.maxStudents !== null && activeRangeSub?.pricingTier?.maxStudents !== undefined) {
      const maxStudents = activeRangeSub.pricingTier!.maxStudents as number;
      const activeStudents = await prisma.student.count({
        where: { institutionId: session.institutionId!, status: "ACTIVE" },
      });
      if (activeStudents >= maxStudents) {
        return NextResponse.json(
          {
            error: "RANGE_LIMIT_REACHED",
            range: `${activeRangeSub.pricingTier!.minStudents}-${maxStudents}`,
            maxStudents,
          },
          { status: 403 }
        );
      }
    }

    const customRoll = String(body.roll ?? "").trim();
    if (customRoll) {
      const taken = await prisma.student.findFirst({
        where: { institutionId: session.institutionId!, roll: customRoll },
        select: { id: true },
      });
      if (taken) {
        return NextResponse.json({ error: "ROLL_EXISTS" }, { status: 409 });
      }
    }

    const result = await prisma.$transaction(async (tx) => {
      let roll = customRoll;
      if (!roll) {
        const count = await tx.student.count({ where: { institutionId: session.institutionId! } });
        roll = String(1001 + count);
      }

      const student = await tx.student.create({
        data: {
          institutionId: session.institutionId!,
          admissionId: admission.id,
          roll,
          name: admission.studentName,
          nameBn: admission.studentNameBn,
          gender: admission.gender,
          dob: admission.dob,
          guardianName: admission.guardianName,
          guardianNameBn: admission.guardianNameBn,
          guardianPhone: admission.guardianPhone,
          motherName: admission.motherName,
          motherNameBn: admission.motherNameBn,
          address: admission.address,
          bloodGroup: admission.bloodGroup || null,
          classItemId: admission.classItemId,
        },
      });
      const updated = await tx.admission.update({
        where: { id: admissionId },
        data: { status: "APPROVED", decidedAt: new Date() },
      });
      return { admission: updated, student };
    });
    return NextResponse.json(result);
  } catch {
    return NextResponse.json({ error: "Could not approve" }, { status: 500 });
  }
}
