import uuid

from django.conf import settings
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.db import models
from django.utils import timezone


# ─── Custom User Manager ────────────────────────────────────────────────────

class UserProfileManager(BaseUserManager):
    """Manager for custom user profiles."""

    def create_user(self, email, first_name='', last_name='', password=None, **extra_fields):
        """Create and return a regular user."""
        if not email:
            raise ValueError("L'adresse email est obligatoire.")

        email = self.normalize_email(email)
        extra_fields.setdefault('is_staff', False)
        extra_fields.setdefault('is_superuser', False)
        extra_fields.setdefault('is_active', False)

        user = self.model(
            email=email,
            first_name=first_name,
            last_name=last_name,
            **extra_fields,
        )

        if password:
            user.set_password(password)
        else:
            user.set_unusable_password()

        user.save(using=self._db)
        return user

    def create_superuser(self, email, first_name='', last_name='', password=None, **extra_fields):
        """Create and return a superuser."""
        extra_fields['is_staff'] = True
        extra_fields['is_superuser'] = True
        extra_fields['is_active'] = True
        extra_fields['is_email_verified'] = True
        extra_fields['is_validated_by_staff'] = True

        if not password:
            raise ValueError("Le superuser doit avoir un mot de passe.")

        return self.create_user(email, first_name, last_name, password, **extra_fields)


# ─── Période d'Adhésion Globale ─────────────────────────────────────────────

class MembershipPeriod(models.Model):
    """
    Période d'adhésion globale pour l'association.
    L'adhésion commence en début d'année et se termine en fin d'année.
    Il ne peut y avoir qu'une seule période active à la fois.
    """
    label = models.CharField(
        max_length=100,
        verbose_name="Libellé",
        help_text="Ex: Adhésion 2025-2026",
    )
    start_date = models.DateField(
        verbose_name="Date de début d'adhésion",
        help_text="Date à partir de laquelle les adhésions sont ouvertes",
    )
    end_date = models.DateField(
        verbose_name="Date de fin d'adhésion",
        help_text="Date à laquelle toutes les adhésions expirent",
    )
    is_active = models.BooleanField(
        default=True,
        verbose_name="Période active",
        help_text="Une seule période peut être active à la fois",
    )
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name = "Période d'adhésion"
        verbose_name_plural = "Périodes d'adhésion"
        ordering = ['-start_date']

    def __str__(self):
        status = "✅ Active" if self.is_active else "❌ Inactive"
        return f"{self.label} ({self.start_date} → {self.end_date}) {status}"

    def clean(self):
        from django.core.exceptions import ValidationError
        if self.start_date and self.end_date and self.start_date >= self.end_date:
            raise ValidationError("La date de début doit être antérieure à la date de fin.")

    def save(self, *args, **kwargs):
        # Enforce singleton: only one active period at a time
        if self.is_active:
            MembershipPeriod.objects.filter(is_active=True).exclude(pk=self.pk).update(is_active=False)
        super().save(*args, **kwargs)

    @classmethod
    def get_current(cls):
        """Retourne la période d'adhésion active actuelle."""
        return cls.objects.filter(is_active=True).first()

    @property
    def is_expired(self):
        """Vérifie si la période est expirée."""
        return timezone.now().date() > self.end_date

    @property
    def is_registration_open(self):
        """Vérifie si les inscriptions sont ouvertes (entre start_date et end_date)."""
        today = timezone.now().date()
        return self.start_date <= today <= self.end_date


# ─── User Profile ───────────────────────────────────────────────────────────

class UserProfile(AbstractBaseUser, PermissionsMixin):
    """Custom user model using email as the unique identifier."""

    # Identité
    email = models.EmailField(max_length=255, unique=True, verbose_name="Email")
    first_name = models.CharField(max_length=30, blank=True, verbose_name="Prénom")
    last_name = models.CharField(max_length=30, blank=True, verbose_name="Nom")
    speciality = models.CharField(max_length=50, blank=True, verbose_name="Spécialité")
    phone_number = models.CharField(max_length=20, blank=True, verbose_name="Téléphone")

    # Fichiers
    document = models.FileField(
        upload_to="documents/",
        null=True,
        blank=True,
        verbose_name="Document justificatif",
    )
    profile_image = models.ImageField(
        upload_to="profiles/",
        null=True,
        blank=True,
        verbose_name="Photo de profil",
    )

    address = models.TextField(blank=True, verbose_name="Adresse complète")

    # Membership / QR Code
    membership_id = models.UUIDField(
        default=uuid.uuid4,
        unique=True,
        editable=False,
        verbose_name="Numéro d'adhérent",
        help_text="Identifiant unique pour le QR code d'inscription",
    )
    qr_code = models.ImageField(
        upload_to="qrcodes/",
        null=True,
        blank=True,
        verbose_name="QR Code",
    )

    # Status flags
    is_active = models.BooleanField(
        default=False,
        verbose_name="Compte actif",
        help_text="Activé par l'agent après réception du paiement",
    )
    is_staff = models.BooleanField(default=False, verbose_name="Staff")
    is_email_verified = models.BooleanField(
        default=False,
        verbose_name="Email vérifié",
        help_text="Étape 1 : l'utilisateur a confirmé son email",
    )
    is_validated_by_staff = models.BooleanField(
        default=False,
        verbose_name="Validé par l'administration",
        help_text="Étape 2 : l'agent a validé le paiement",
    )

    # Dates
    date_joined = models.DateTimeField(default=timezone.now, verbose_name="Date d'inscription")
    membership_activated_at = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name="Date d'activation de l'adhésion",
        help_text="Date à laquelle le staff a validé le paiement et activé le compte. Re-stampée à chaque réactivation.",
    )
    membership_period = models.ForeignKey(
        MembershipPeriod,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='members',
        verbose_name="Période d'adhésion",
        help_text="Période d'adhésion globale assignée à cet utilisateur",
    )

    objects = UserProfileManager()

    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = ["first_name", "last_name"]

    class Meta:
        verbose_name = "Compte Utilisateur"
        verbose_name_plural = "Comptes Utilisateurs"
        ordering = ['-date_joined']

    def __str__(self):
        full = self.get_full_name()
        return f"{full} ({self.email})" if full else self.email

    def get_full_name(self):
        return f"{self.first_name} {self.last_name}".strip()

    def get_short_name(self):
        return self.first_name or self.email.split('@')[0]

    @property
    def is_membership_valid(self):
        """Vérifie si l'adhésion est encore valide par rapport à la période globale."""
        if self.membership_period:
            return not self.membership_period.is_expired
        return False

    def has_validated_receipt_for(self, period):
        """True si un reçu validé existe pour la période passée en argument."""
        if not period:
            return False
        return self.payment_receipts.filter(
            is_validated=True,
            membership_period=period,
        ).exists()

    @property
    def has_paid_current_period(self):
        """True si un reçu validé existe pour la période globale active actuelle."""
        return self.has_validated_receipt_for(MembershipPeriod.get_current())


# ─── Paiement & Reçus ───────────────────────────────────────────────────────

class PaymentReceipt(models.Model):
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="payment_receipts",
        verbose_name="Adhérent"
    )
    membership_period = models.ForeignKey(
        'MembershipPeriod',
        on_delete=models.PROTECT,
        related_name='payment_receipts',
        null=True,
        blank=True,
        verbose_name="Période d'adhésion",
        help_text="Période d'adhésion pour laquelle ce reçu est émis.",
    )
    receipt_file = models.FileField(
        upload_to="receipts/",
        verbose_name="Fichier du reçu (Image/PDF)"
    )
    payment_date = models.DateField(
        default=timezone.now,
        verbose_name="Date de paiement"
    )
    amount = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        default=0.00,
        verbose_name="Montant payé"
    )
    is_validated = models.BooleanField(
        default=False,
        verbose_name="Validé par l'administration"
    )
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name = "Reçu de paiement"
        verbose_name_plural = "Reçus de paiement"
        ordering = ['-payment_date', '-created_at']

    def __str__(self):
        period_label = f" ({self.membership_period.label})" if self.membership_period else ""
        return f"Reçu de {self.user.get_full_name()} du {self.payment_date}{period_label}"

