"""
Mixins CMS pour l'integration des pages avec les modeles et vues.
"""
from django.db import models
from django.utils.text import slugify
from django.utils.translation import gettext_lazy as _


class CMSPageableMixin(models.Model):
    """
    Mixin pour les modeles qui doivent etre lies a une Page CMS.

    Chaque instance du modele peut avoir sa propre Page CMS associee.
    Cela permet de personnaliser le template et les sections pour chaque instance.

    Utilisation:
        class ApplicationCall(CMSPageableMixin, models.Model):
            academic_year = models.CharField(...)

            class Meta:
                # Pour la generation auto du slug de page
                cms_page_prefix = 'appel-candidature'

        # Creer automatiquement une page CMS pour une instance
        call = ApplicationCall.objects.get(pk=1)
        page = call.get_or_create_cms_page()

    Attributs de classe a definir (optionnels):
        cms_page_prefix: Prefixe pour le slug de la page (defaut: nom du modele)
        cms_default_template_slug: Slug du template CMS a utiliser par defaut
    """
    cms_page = models.ForeignKey(
        'cms.Page',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='%(app_label)s_%(class)s_instances',
        verbose_name=_("Page CMS"),
        help_text=_("Page CMS associee a cette instance")
    )

    class Meta:
        abstract = True

    def get_cms_page_slug(self):
        """
        Genere le slug unique pour la page CMS de cette instance.

        Peut etre surcharge dans les modeles enfants pour personnaliser.

        Recherche l'attribut CMS_PAGE_PREFIX sur la classe, sinon utilise le nom du modele.
        """
        # Chercher l'attribut de classe CMS_PAGE_PREFIX
        prefix = getattr(self.__class__, 'CMS_PAGE_PREFIX', None)
        if not prefix:
            prefix = self._meta.model_name

        # Utiliser un identifiant unique pour l'instance
        identifier = self.get_cms_page_identifier()
        return f"{prefix}-{slugify(str(identifier))}"

    def get_cms_page_identifier(self):
        """
        Retourne l'identifiant unique a utiliser pour le slug de la page.

        Par defaut utilise le pk. A surcharger pour utiliser un autre champ.
        Ex: pour ApplicationCall, retourner self.academic_year
        """
        return self.pk

    def get_cms_page_title(self):
        """
        Retourne le titre par defaut de la page CMS.

        Par defaut utilise __str__. A surcharger si necessaire.
        """
        return str(self)

    def get_cms_page_name(self):
        """
        Retourne le nom interne de la page CMS.

        Par defaut utilise le titre. A surcharger si necessaire.
        """
        return self.get_cms_page_title()

    def get_default_template(self):
        """
        Retourne le Template CMS par defaut pour ce modele.

        Cherche un template avec le slug defini dans cms_default_template_slug
        ou le premier template actif.
        """
        from cms.models import Template

        template_slug = getattr(self._meta, 'cms_default_template_slug', None)
        if template_slug:
            try:
                return Template.objects.get(slug=template_slug, is_active=True)
            except Template.DoesNotExist:
                pass

        # Fallback: premier template actif
        return Template.objects.filter(is_active=True).first()

    def get_or_create_cms_page(self, template=None):
        """
        Recupere ou cree la page CMS pour cette instance.

        Args:
            template: Template CMS a utiliser (optionnel)

        Returns:
            Page CMS associee
        """
        from cms.models import Page

        if self.cms_page:
            return self.cms_page

        # Determiner le template
        if not template:
            template = self.get_default_template()

        if not template:
            raise ValueError("Aucun template CMS disponible. Creez d'abord un Template.")

        # Generer le slug unique
        slug = self.get_cms_page_slug()

        # Verifier si une page avec ce slug existe deja
        try:
            page = Page.objects.get(slug=slug)
        except Page.DoesNotExist:
            # Creer la page
            page = Page.objects.create(
                name=self.get_cms_page_name(),
                slug=slug,
                title=self.get_cms_page_title(),
                template=template,
                is_active=True
            )

        # Associer la page a l'instance
        self.cms_page = page
        self.save(update_fields=['cms_page'])

        return page

    def ensure_cms_page(self, template=None):
        """
        Alias pour get_or_create_cms_page.
        Utilise pour la clarte dans les signaux ou les vues.
        """
        return self.get_or_create_cms_page(template=template)

    def delete_cms_page(self):
        """
        Supprime la page CMS associee.

        Utile pour le nettoyage lors de la suppression de l'instance.
        """
        if self.cms_page:
            page = self.cms_page
            self.cms_page = None
            self.save(update_fields=['cms_page'])
            page.delete()


class CMSPageableAutoCreateMixin(CMSPageableMixin):
    """
    Extension de CMSPageableMixin qui cree automatiquement la page CMS
    lors de la sauvegarde de l'instance.

    Utile pour les modeles ou chaque instance doit avoir une page CMS.
    """

    class Meta:
        abstract = True

    def save(self, *args, **kwargs):
        # Sauvegarder d'abord l'instance pour avoir un pk
        is_new = self.pk is None
        super().save(*args, **kwargs)

        # Creer la page CMS si nouvelle instance et pas de page associee
        if is_new and not self.cms_page:
            try:
                self.get_or_create_cms_page()
            except ValueError:
                # Pas de template disponible, ignorer silencieusement
                pass
