import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/infrastructure/db/prisma";
import { updateEvent, validateFutureDate } from "@/infrastructure/external/calendar";
import { sendRescheduleConfirmation } from "@/infrastructure/email/smtp";
import { deleteCachePattern } from "@/infrastructure/cache/redis";
import { getAvailability } from "@/infrastructure/external/calendar";

export async function POST(request: NextRequest) {
  try {
    const body = await request.json();
    const { appointmentId, newDate, reason } = body;

    if (!appointmentId || !newDate) {
      return NextResponse.json(
        { success: false, message: "appointmentId y newDate son requeridos" },
        { status: 400 }
      );
    }

    const parsedNewDate = new Date(newDate);
    if (isNaN(parsedNewDate.getTime())) {
      return NextResponse.json({ success: false, message: "Fecha inválida" }, { status: 400 });
    }

    if (!validateFutureDate(parsedNewDate)) {
      return NextResponse.json(
        {
          success: false,
          message: "La fecha debe estar en el futuro y dentro de los próximos 7 días",
        },
        { status: 400 }
      );
    }

    const appointment = await prisma.appointment.findUnique({
      where: { id: parseInt(appointmentId) },
      include: {
        patient: true,
      },
    });

    if (!appointment) {
      return NextResponse.json({ success: false, message: "Cita no encontrada" }, { status: 404 });
    }

    const slotStart = parsedNewDate;
    const slotEnd = new Date(parsedNewDate.getTime() + 60 * 60000);

    const slots = await getAvailability({
      startDate: new Date(parsedNewDate.setHours(0, 0, 0, 0)),
      endDate: new Date(parsedNewDate.setHours(23, 59, 59, 999)),
    });

    const isAvailable = slots.some(
      (slot) => slot.startTime <= slotStart && slot.endTime >= slotEnd && slot.available
    );

    if (!isAvailable) {
      return NextResponse.json(
        { success: false, message: "Este horario ya está ocupado. Por favor selecciona otro." },
        { status: 409 }
      );
    }

    if (appointment.eventId) {
      await updateEvent(
        appointment.eventId,
        parsedNewDate,
        undefined,
        reason ? `\n\nRazón de reacomodación: ${reason}` : undefined
      );
    }

    const updatedAppointment = await prisma.appointment.update({
      where: { id: parseInt(appointmentId) },
      data: {
        date: parsedNewDate,
      },
      include: {
        patient: true,
      },
    });

    await deleteCachePattern("availability:*");

    if (appointment.patient.email) {
      await sendRescheduleConfirmation(
        appointment.patient.email,
        appointment.patient.name,
        appointment.date,
        parsedNewDate
      );
    }

    return NextResponse.json({
      success: true,
      message: "Cita reacomodada exitosamente",
      appointment: updatedAppointment,
    });
  } catch (error) {
    console.error("[Reschedule] Error:", error);
    return NextResponse.json(
      { success: false, message: "Error al reacomodar la cita" },
      { status: 500 }
    );
  }
}
