"use server";

import { z } from "zod";
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { prisma } from "@/lib/prisma";
import { auth } from "@/auth";
import { calculateNights } from "@/lib/utils";

const reservationSchema = z.object({
  client_id: z.string().min(1, "Client requis"),
  chambre_id: z.string().min(1, "Chambre requise"),
  date_arrivee: z.string().min(1, "Date d'arrivée requise"),
  date_depart: z.string().min(1, "Date de départ requise"),
  nb_personnes: z.coerce.number().min(1).default(1),
  statut: z.enum(["CONFIRMEE", "EN_ATTENTE", "ANNULEE", "TERMINEE"]).default("CONFIRMEE"),
  notes: z.string().optional().default(""),
});

// Vérification du chevauchement de réservation pour une chambre
async function checkOverlap(
  chambreId: string,
  arrivee: Date,
  depart: Date,
  excludeId?: string
) {
  const overlap = await prisma.reservation.findFirst({
    where: {
      chambre_id: chambreId,
      statut: { in: ["CONFIRMEE", "EN_ATTENTE"] },
      NOT: excludeId ? { id: excludeId } : undefined,
      // Chevauchement : (arrivée_existante < départ_demandé) ET (départ_existant > arrivée_demandée)
      AND: [
        { date_arrivee: { lt: depart } },
        { date_depart: { gt: arrivee } },
      ],
    },
    include: { client: true },
  });
  return overlap;
}

// Recherche des chambres disponibles pour une période donnée
export async function getChambresDisponibles(
  arrivee: Date,
  depart: Date
): Promise<{ id: string; numero: string; type: string; prix_nuit: number; capacite: number }[]> {
  const allChambres = await prisma.chambre.findMany({
    where: { statut: { notIn: ["MAINTENANCE"] } },
    orderBy: { numero: "asc" },
  });

  const reservationsConflit = await prisma.reservation.findMany({
    where: {
      statut: { in: ["CONFIRMEE", "EN_ATTENTE"] },
      AND: [
        { date_arrivee: { lt: depart } },
        { date_depart: { gt: arrivee } },
      ],
    },
    select: { chambre_id: true },
  });

  const occupees = new Set(reservationsConflit.map((r) => r.chambre_id));
  return allChambres.filter((c) => !occupees.has(c.id));
}

export async function createReservation(formData: FormData) {
  const session = await auth();
  if (!session) return { error: "Non authentifié" };

  const raw = Object.fromEntries(formData.entries());
  const parsed = reservationSchema.safeParse(raw);
  if (!parsed.success) return { error: parsed.error.issues[0].message };

  const arrivee = new Date(parsed.data.date_arrivee);
  const depart = new Date(parsed.data.date_depart);

  if (depart <= arrivee) {
    return { error: "La date de départ doit être après la date d'arrivée" };
  }

  // Vérification de chevauchement
  const overlap = await checkOverlap(parsed.data.chambre_id, arrivee, depart);
  if (overlap) {
    return {
      error: `Cette chambre est déjà réservée par ${overlap.client.nom_complet} pour cette période`,
    };
  }

  const chambre = await prisma.chambre.findUnique({
    where: { id: parsed.data.chambre_id },
  });
  if (!chambre) return { error: "Chambre introuvable" };

  const nb_nuits = calculateNights(arrivee, depart);
  const prix_total = nb_nuits * chambre.prix_nuit;

  const reservation = await prisma.reservation.create({
    data: {
      client_id: parsed.data.client_id,
      chambre_id: parsed.data.chambre_id,
      date_arrivee: arrivee,
      date_depart: depart,
      nb_nuits,
      nb_personnes: parsed.data.nb_personnes,
      prix_total,
      statut: parsed.data.statut,
      notes: parsed.data.notes,
    },
  });

  revalidatePath("/reservations");
  revalidatePath("/calendrier");
  revalidatePath("/");
  redirect(`/reservations/${reservation.id}`);
}

export async function updateReservation(id: string, formData: FormData) {
  const session = await auth();
  if (!session) return { error: "Non authentifié" };

  const raw = Object.fromEntries(formData.entries());
  const parsed = reservationSchema.safeParse(raw);
  if (!parsed.success) return { error: parsed.error.issues[0].message };

  const existing = await prisma.reservation.findUnique({ where: { id } });
  if (!existing) return { error: "Réservation introuvable" };
  if (existing.statut === "TERMINEE") {
    return { error: "Impossible de modifier une réservation terminée" };
  }

  const arrivee = new Date(parsed.data.date_arrivee);
  const depart = new Date(parsed.data.date_depart);
  if (depart <= arrivee) {
    return { error: "La date de départ doit être après la date d'arrivée" };
  }

  // Si on n'annule pas, vérifier le chevauchement
  if (parsed.data.statut !== "ANNULEE") {
    const overlap = await checkOverlap(parsed.data.chambre_id, arrivee, depart, id);
    if (overlap) {
      return {
        error: `Cette chambre est déjà réservée par ${overlap.client.nom_complet} pour cette période`,
      };
    }
  }

  const chambre = await prisma.chambre.findUnique({
    where: { id: parsed.data.chambre_id },
  });
  if (!chambre) return { error: "Chambre introuvable" };

  const nb_nuits = calculateNights(arrivee, depart);
  const prix_total = nb_nuits * chambre.prix_nuit;

  await prisma.reservation.update({
    where: { id },
    data: {
      client_id: parsed.data.client_id,
      chambre_id: parsed.data.chambre_id,
      date_arrivee: arrivee,
      date_depart: depart,
      nb_nuits,
      nb_personnes: parsed.data.nb_personnes,
      prix_total,
      statut: parsed.data.statut,
      notes: parsed.data.notes,
    },
  });

  revalidatePath("/reservations");
  revalidatePath(`/reservations/${id}`);
  revalidatePath("/calendrier");
  revalidatePath("/");
  redirect(`/reservations/${id}`);
}

export async function cancelReservation(id: string) {
  const session = await auth();
  if (!session) return { error: "Non authentifié" };

  const reservation = await prisma.reservation.findUnique({
    where: { id },
    include: { chambre: true },
  });
  if (!reservation) return { error: "Réservation introuvable" };

  await prisma.$transaction([
    prisma.reservation.update({ where: { id }, data: { statut: "ANNULEE" } }),
    // Si la chambre était occupée par cette résa, libération
    ...(reservation.chambre.statut === "OCCUPEE"
      ? [
          prisma.chambre.update({
            where: { id: reservation.chambre_id },
            data: { statut: "DISPONIBLE" },
          }),
        ]
      : []),
  ]);

  revalidatePath("/reservations");
  revalidatePath(`/reservations/${id}`);
  revalidatePath("/calendrier");
  revalidatePath("/");
  return { success: true };
}
