from django.db import models
from django.conf import settings
from django.utils import timezone


class SlotTemplate(models.Model):
    """
    Template pour générer des créneaux automatiquement (ex: chaque lundi 9h-17h, 30 min).
    Utilisé pour créer des AppointmentSlot pour les semaines à venir.
    """
    WEEKDAYS = [
        (0, "Lundi"),
        (1, "Mardi"),
        (2, "Mercredi"),
        (3, "Jeudi"),
        (4, "Vendredi"),
        (5, "Samedi"),
        (6, "Dimanche"),
    ]
    weekday = models.PositiveSmallIntegerField(choices=WEEKDAYS, verbose_name="Jour de la semaine")
    start_time = models.TimeField(verbose_name="Heure début (ex: 09:00)")
    end_time = models.TimeField(verbose_name="Heure fin (ex: 17:00)")
    slot_duration_minutes = models.PositiveIntegerField(
        default=30,
        verbose_name="Durée d'un créneau (minutes)",
        help_text="Ex: 30 pour des créneaux de 30 min.",
    )
    is_online = models.BooleanField(default=False, verbose_name="Visio (en ligne)")
    meet_link = models.URLField(blank=True, default="", verbose_name="Lien Meet / visio")
    location_notes = models.CharField(
        max_length=500,
        blank=True,
        default="",
        verbose_name="Lieu ou instructions (présentiel)",
    )
    is_active = models.BooleanField(default=True, verbose_name="Actif")
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ["weekday", "start_time"]
        verbose_name = "Template de créneaux"
        verbose_name_plural = "Templates de créneaux"

    def __str__(self):
        return f"{self.get_weekday_display()} {self.start_time}-{self.end_time} ({self.slot_duration_minutes} min)"


class AppointmentSlot(models.Model):
    """
    Un créneau concret : une date + un intervalle horaire.
    Une fois réservé (via Appointment), il n'est plus disponible.
    """
    date = models.DateField(verbose_name="Date")
    start_time = models.TimeField(verbose_name="Heure début")
    end_time = models.TimeField(verbose_name="Heure fin")
    is_online = models.BooleanField(default=False, verbose_name="Visio")
    meet_link = models.URLField(blank=True, default="", verbose_name="Lien Meet")
    location_notes = models.CharField(max_length=500, blank=True, default="", verbose_name="Lieu (présentiel)")
    created_at = models.DateTimeField(auto_now_add=True)
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="created_appointment_slots",
        verbose_name="Créé par",
    )
    template = models.ForeignKey(
        SlotTemplate,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="generated_slots",
        verbose_name="Template source",
    )

    class Meta:
        ordering = ["date", "start_time"]
        verbose_name = "Créneau"
        verbose_name_plural = "Créneaux"
        unique_together = [["date", "start_time"]]

    def __str__(self):
        return f"{self.date} {self.start_time}-{self.end_time}"

    @property
    def is_available(self):
        """True si aucun rendez-vous actif sur ce créneau (ou annulé / no-show)."""
        try:
            return self.appointment.status in (
                Appointment.Status.CANCELLED,
                Appointment.Status.NO_SHOW,
            )
        except Appointment.DoesNotExist:
            return True


class Appointment(models.Model):
    """
    Rendez-vous réservé. Tout le monde peut réserver ; on demande email (et nom) si pas connecté.
    """
    class Status(models.TextChoices):
        PENDING = "PENDING", "En attente"
        CONFIRMED = "CONFIRMED", "Confirmé"
        CANCELLED = "CANCELLED", "Annulé"
        COMPLETED = "COMPLETED", "Effectué"
        NO_SHOW = "NO_SHOW", "Absent"

    slot = models.OneToOneField(
        AppointmentSlot,
        on_delete=models.CASCADE,
        related_name="appointment",
        verbose_name="Créneau",
    )
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="appointments",
        verbose_name="Utilisateur (si connecté)",
    )
    guest_email = models.EmailField(verbose_name="Email")
    guest_name = models.CharField(max_length=255, blank=True, default="", verbose_name="Nom (invité)")
    status = models.CharField(
        max_length=20,
        choices=Status.choices,
        default=Status.PENDING,
    )
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    email_sent_at = models.DateTimeField(null=True, blank=True, verbose_name="Email envoyé le")
    confirmed_at = models.DateTimeField(null=True, blank=True, verbose_name="Confirmé le")
    admin_notes = models.TextField(blank=True, default="", verbose_name="Notes admin")

    class Meta:
        ordering = ["-created_at"]
        verbose_name = "Rendez-vous"
        verbose_name_plural = "Rendez-vous"

    def __str__(self):
        return f"{self.guest_email} – {self.slot.date} {self.slot.start_time}"
