// src/app/api/admin/schedule-requests/[id]/route.ts
import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { getAdminUser } from "@/lib/auth";
import { parseDateUTC, fmt12 } from "@/lib/timeslot-utils";
import { sendMail } from "@/lib/mailer";
import {
  scheduleRequestApprovedEmailTemplate,
  scheduleRequestRejectedEmailTemplate,
} from "@/lib/email-templates";

export async function PATCH(
  req: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  const admin = await getAdminUser();
  if (!admin) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });

  const { id } = await params;
  const requestId = Number(id);
  const body = await req.json();
  const { action, admin_note } = body as { action: "approve" | "reject"; admin_note?: string };

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

  const changeRequest = await prisma.schedule_change_requests.findUnique({
    where: { id: requestId },
    include: {
      schedule_bookings: {
        include: {
          time_slots: { select: { start_time: true, end_time: true } },
          student_schedules: {
            include: { students: { select: { name: true, email: true } } },
          },
        },
      },
    },
  });

  if (!changeRequest) {
    return NextResponse.json({ error: "Request not found" }, { status: 404 });
  }
  if (changeRequest.status !== "pending") {
    return NextResponse.json({ error: "This request has already been processed" }, { status: 400 });
  }

  const student = changeRequest.schedule_bookings?.student_schedules.students;
  const currentSlot = changeRequest.schedule_bookings?.time_slots;
  const currentDateLabel = changeRequest.current_booking_date
    ? changeRequest.current_booking_date.toISOString().slice(0, 10)
    : changeRequest.schedule_bookings?.booking_date.toISOString().slice(0, 10) ?? "—";
  const requestedDateLabel = changeRequest.requested_date.toISOString().slice(0, 10);

  // --- REJECT: just update the request, nothing else changes ---
  if (action === "reject") {
    const updated = await prisma.schedule_change_requests.update({
      where: { id: requestId },
      data: { status: "rejected", admin_note: admin_note ?? null },
    });

    if (student && currentSlot) {
      try {
        await sendMail({
          to: student.email,
          subject: "Your RKDA schedule change request was not approved",
          html: scheduleRequestRejectedEmailTemplate(
            student.name,
            {
              dateLabel: currentDateLabel,
              startTime: fmt12(currentSlot.start_time),
              endTime: fmt12(currentSlot.end_time),
            },
            {
              dateLabel: requestedDateLabel,
              startTime: fmt12(changeRequest.requested_start_time),
              endTime: fmt12(changeRequest.requested_end_time),
            },
            admin_note ?? null,
            `${process.env.NEXT_PUBLIC_APP_URL}/student/schedule`
          ),
        });
      } catch (mailErr) {
        console.error("Schedule Reject Email Error:", mailErr);
      }
    }

    return NextResponse.json({ data: updated });
  }

  // --- APPROVE: move the booking to the new slot, inside a transaction ---
  if (!changeRequest.booking_id || !changeRequest.schedule_bookings) {
    return NextResponse.json({ error: "This request has no linked booking" }, { status: 400 });
  }

  try {
    const result = await prisma.$transaction(async (tx) => {
      const oldBooking = changeRequest.schedule_bookings!;

      // 1. Find the target slot for the requested date/time
      const targetSlot = await tx.time_slots.findFirst({
        where: {
          slot_date: parseDateUTC(changeRequest.requested_date.toISOString().slice(0, 10)),
          start_time: changeRequest.requested_start_time,
          end_time: changeRequest.requested_end_time,
          active_status: true,
        },
      });

      if (!targetSlot) {
        throw new Error("SLOT_NOT_FOUND");
      }

      // 2. Reserve capacity on the new slot atomically (fails if it filled up
      //    while this request was pending)
      const reserve = await tx.time_slots.updateMany({
        where: { id: targetSlot.id, booked_count: { lt: targetSlot.capacity } },
        data: { booked_count: { increment: 1 } },
      });

      if (reserve.count === 0) {
        throw new Error("SLOT_FULL");
      }

      // 3. Free up capacity on the old slot
      await tx.time_slots.update({
        where: { id: oldBooking.time_slot_id },
        data: { booked_count: { decrement: 1 } },
      });

      // 4. Move the booking to the new slot/date
      const updatedBooking = await tx.schedule_bookings.update({
        where: { id: oldBooking.id },
        data: {
          time_slot_id: targetSlot.id,
          booking_date: changeRequest.requested_date,
        },
      });

      // 5. Mark the request approved
      const updatedRequest = await tx.schedule_change_requests.update({
        where: { id: requestId },
        data: { status: "approved", admin_note: admin_note ?? null },
      });

      return { updatedBooking, updatedRequest, targetSlot };
    });

    // Send approval email — old vs new slot. Captured before the transaction
    // ran (currentSlot/currentDateLabel), so this reflects the true "before".
    if (student && currentSlot) {
      try {
        await sendMail({
          to: student.email,
          subject: "Your RKDA schedule change request was approved",
          html: scheduleRequestApprovedEmailTemplate(
            student.name,
            {
              dateLabel: currentDateLabel,
              startTime: fmt12(currentSlot.start_time),
              endTime: fmt12(currentSlot.end_time),
            },
            {
              dateLabel: requestedDateLabel,
              startTime: fmt12(result.targetSlot.start_time),
              endTime: fmt12(result.targetSlot.end_time),
            },
            `${process.env.NEXT_PUBLIC_APP_URL}/student/schedule`
          ),
        });
      } catch (mailErr) {
        console.error("Schedule Approve Email Error:", mailErr);
      }
    }

    return NextResponse.json({ data: result });
  } catch (err: any) {
    if (err.message === "SLOT_NOT_FOUND") {
      return NextResponse.json({ error: "The requested time slot no longer exists." }, { status: 400 });
    }
    if (err.message === "SLOT_FULL") {
      return NextResponse.json({ error: "The requested time slot is now full." }, { status: 409 });
    }
    console.error(err);
    return NextResponse.json({ error: "Failed to approve request." }, { status: 500 });
  }
}