from django.views.generic import TemplateView, DetailView, ListView
from django.shortcuts import get_object_or_404
from django.http import Http404
from traduction.helpers import prefetch_translations
from .models import CarouselSlide, ProgramStatistic, Partner, UniversityMapSettings


class CMSPageMixin:
    """
    Mixin pour integrer les pages CMS dans les vues.

    Utilisation:
        - La vue cherche d'abord une Page CMS correspondante
        - Si trouvee, utilise le template du Template CMS
        - Sinon, utilise le template_name par defaut
    """
    cms_page_slug = None  # Slug de la page CMS a utiliser

    def get_cms_page(self):
        """Recupere la page CMS si elle existe."""
        from cms.models import Page

        slug = self.cms_page_slug
        if not slug:
            return None

        try:
            return Page.objects.select_related('template').prefetch_related(
                'pagesection_set__section__template'
            ).get(slug=slug, is_active=True)
        except Page.DoesNotExist:
            return None

    def get_template_names(self):
        """Utilise le template CMS si la page existe."""
        page = getattr(self, '_cms_page', None)
        if page:
            return [page.get_template_name()]
        return super().get_template_names()

    def get_context_data(self, **kwargs):
        """Ajoute la page CMS au contexte."""
        # Recupere et cache la page CMS
        self._cms_page = self.get_cms_page()

        context = super().get_context_data(**kwargs)
        if self._cms_page:
            context['page'] = self._cms_page
            context['cms_page'] = self._cms_page
        return context


class HomePageView(CMSPageMixin, TemplateView):
    """
    Vue de la page d'accueil.

    Logique:
        1. Cherche une Page CMS avec is_homepage=True
        2. Si trouvee, utilise ses sections ordonnees
        3. Sinon, utilise le template par defaut

    Les sections sont rendues via include_section qui charge
    le template correspondant (ex: cms_home/sections/hero.html)
    """
    template_name = 'core/home.html'

    def get_cms_page(self):
        """Recupere la page d'accueil CMS."""
        from cms.models import Page

        try:
            return Page.objects.select_related('template').prefetch_related(
                'pagesection_set__section__template'
            ).get(is_homepage=True, is_active=True)
        except Page.DoesNotExist:
            return None

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        # Configuration de la carte des universités (specifique a cette vue)
        context['map_settings'] = UniversityMapSettings.get_settings()

        # Note: Les donnees suivantes sont deja fournies par le context processor
        # avec les traductions appliquees:
        # - slides (carousel_slides)
        # - statistics (program_stats)
        # - partners
        # - main_partner
        # - universities
        # - research_areas
        # - featured_team
        # - latest_news (avec traductions)
        # - upcoming_events (avec traductions)

        return context


class CMSPageView(CMSPageMixin, TemplateView):
    """
    Vue generique pour afficher une page CMS par son slug.

    Usage dans urls.py:
        path('about/', CMSPageView.as_view(cms_page_slug='about'), name='about')

    Ou avec capture d'URL:
        path('page/<slug:slug>/', CMSPageView.as_view(), name='cms_page')
    """
    template_name = 'cms/page.html'  # Template de fallback

    def get_cms_page(self):
        """Recupere la page CMS par slug (URL ou attribut)."""
        from cms.models import Page

        # Priorite au slug dans l'URL
        slug = self.kwargs.get('slug') or self.cms_page_slug
        if not slug:
            return None

        try:
            return Page.objects.select_related('template').prefetch_related(
                'pagesection_set__section__template'
            ).get(slug=slug, is_active=True)
        except Page.DoesNotExist:
            return None

    def get(self, request, *args, **kwargs):
        # Verifie que la page existe
        self._cms_page = self.get_cms_page()
        if not self._cms_page and self.kwargs.get('slug'):
            raise Http404("Page non trouvee")
        return super().get(request, *args, **kwargs)


class CMSObjectMixin:
    """
    Mixin pour les vues qui affichent un objet avec une page CMS associee.

    L'objet doit utiliser CMSPageableMixin pour avoir un champ cms_page.
    Si l'objet a une page CMS, elle est utilisee pour le template.
    Sinon, le template par defaut est utilise.

    Attributs de classe:
        cms_auto_create_page: Si True, cree automatiquement la page CMS si absente
        cms_default_template_slug: Slug du template par defaut pour creation auto
    """
    cms_auto_create_page = False
    cms_default_template_slug = None

    def get_language_code(self):
        """Recupere le code de langue courant."""
        return getattr(self.request, 'current_language_code', 'fr')

    def get_cms_page_from_object(self, obj):
        """
        Recupere la page CMS depuis l'objet.

        Si cms_auto_create_page est True et l'objet n'a pas de page,
        une page est creee automatiquement.
        """
        if not hasattr(obj, 'cms_page'):
            return None

        if obj.cms_page:
            return obj.cms_page

        # Creation automatique si demandee
        if self.cms_auto_create_page and hasattr(obj, 'get_or_create_cms_page'):
            try:
                template = None
                if self.cms_default_template_slug:
                    from cms.models import Template
                    try:
                        template = Template.objects.get(
                            slug=self.cms_default_template_slug,
                            is_active=True
                        )
                    except Template.DoesNotExist:
                        pass
                return obj.get_or_create_cms_page(template=template)
            except ValueError:
                pass

        return None

    def get_template_names(self):
        """Utilise le template de la page CMS si disponible."""
        obj = getattr(self, 'object', None)
        if obj:
            page = self.get_cms_page_from_object(obj)
            if page:
                return [page.get_template_name()]
        return super().get_template_names()

    def get_context_data(self, **kwargs):
        """Ajoute la page CMS et les sections au contexte."""
        context = super().get_context_data(**kwargs)
        language_code = self.get_language_code()

        obj = getattr(self, 'object', None)
        if obj:
            page = self.get_cms_page_from_object(obj)
            if page:
                # Prefetch des traductions pour la page
                prefetch_translations([page], language_code=language_code)

                context['page'] = page
                context['cms_page'] = page

                # Charger les sections ordonnees avec traductions
                page_sections = list(page.get_ordered_page_sections())
                if page_sections:
                    sections = [ps.section for ps in page_sections]
                    prefetch_translations(sections, language_code=language_code)
                context['page_sections'] = page_sections

        return context


class CMSDetailView(CMSObjectMixin, DetailView):
    """
    Vue detail generique pour les objets avec page CMS.

    Combine DetailView avec le support CMS pour utiliser automatiquement
    le template de la page CMS associee a l'objet.

    Utilisation:
        class ApplicationCallDetailView(CMSDetailView):
            model = ApplicationCall
            template_name = 'program/call_detail.html'  # Fallback
            context_object_name = 'call'

    Si l'objet ApplicationCall a une page CMS, son template sera utilise.
    Sinon, 'program/call_detail.html' sera utilise.
    """

    def get_object(self, queryset=None):
        """Recupere l'objet avec prefetch de la page CMS."""
        obj = super().get_object(queryset)
        language_code = self.get_language_code()

        # Traduire l'objet principal
        prefetch_translations([obj], language_code=language_code)

        return obj


class CMSListView(CMSPageMixin, ListView):
    """
    Vue liste generique avec support page CMS.

    Utilise le template de la page CMS si cms_page_slug est defini
    et qu'une page correspondante existe.

    Utilisation:
        class NewsListView(CMSListView):
            model = NewsArticle
            template_name = 'news/list.html'  # Fallback
            cms_page_slug = 'actualites'

    Si une page CMS avec slug 'actualites' existe, son template sera utilise.
    """

    def get_language_code(self):
        """Recupere le code de langue courant."""
        return getattr(self.request, 'current_language_code', 'fr')

    def get_context_data(self, **kwargs):
        """Ajoute la page CMS au contexte."""
        # Recupere et cache la page CMS
        self._cms_page = self.get_cms_page()

        context = super().get_context_data(**kwargs)
        language_code = self.get_language_code()

        if self._cms_page:
            # Prefetch des traductions pour la page
            prefetch_translations([self._cms_page], language_code=language_code)

            context['page'] = self._cms_page
            context['cms_page'] = self._cms_page

            # Charger les sections ordonnees avec traductions
            page_sections = list(self._cms_page.get_ordered_page_sections())
            if page_sections:
                sections = [ps.section for ps in page_sections]
                prefetch_translations(sections, language_code=language_code)
            context['page_sections'] = page_sections

        return context
