from django.shortcuts import render, get_object_or_404, redirect
from django.views.generic import ListView, DetailView, TemplateView
from django.contrib import messages
from django.db.models import Q, Prefetch
from django.utils import timezone
from django.db import transaction
from django.core.cache import cache
from django.views.decorators.cache import cache_page
from django.utils.decorators import method_decorator
import logging

from .models import Station, Service, Actualite, PrixCarburant, Contact, Statistique
from .forms import ContactForm

logger = logging.getLogger('django.db.backends')


class DatabaseOptimizedMixin:
    """
    Mixin pour optimiser les requêtes de base de données et gérer les erreurs
    """

    def dispatch(self, request, *args, **kwargs):
        """
        Wrapper pour gérer les erreurs de base de données
        """
        try:
            return super().dispatch(request, *args, **kwargs)
        except Exception as e:
            logger.error(f"Erreur dans {self.__class__.__name__}: {e}")
            # En cas d'erreur, rediriger vers une page d'erreur gracieuse
            return render(request, 'errors/500.html', {'error': str(e)}, status=500)


class AccueilView(DatabaseOptimizedMixin, TemplateView):
    """Vue optimisée pour la page d'accueil"""
    template_name = 'bilal/accueil.html'

    @method_decorator(cache_page(60 * 5))  # Cache pendant 5 minutes
    def dispatch(self, *args, **kwargs):
        return super().dispatch(*args, **kwargs)

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

        try:
            # Utiliser select_related et prefetch_related pour optimiser les requêtes
            with transaction.atomic():
                # Services actifs avec optimisation
                context['services'] = Service.objects.select_related().filter(
                    est_actif=True
                ).order_by('ordre')[:6]

                # Statistiques actives
                context['statistiques'] = Statistique.objects.filter(
                    est_actif=True
                ).order_by('ordre')

                # Prix actuels des carburants
                context['prix_carburants'] = PrixCarburant.objects.filter(
                    est_actuel=True
                ).order_by('type_carburant')

                # Actualités récentes optimisées
                context['actualites_recentes'] = Actualite.objects.select_related().filter(
                    est_publie=True,
                    date_publication__lte=timezone.now()
                ).order_by('-date_publication')[:3]

                # Nombre de stations (utilisation du cache)
                cache_key = 'nombre_stations_actives'
                nombre_stations = cache.get(cache_key)
                if nombre_stations is None:
                    nombre_stations = Station.objects.filter(est_active=True).count()
                    cache.set(cache_key, nombre_stations, 60 * 10)  # Cache 10 minutes

                context['nombre_stations'] = nombre_stations

        except Exception as e:
            logger.error(f"Erreur lors du chargement de l'accueil : {e}")
            # Données par défaut en cas d'erreur
            context.update({
                'services': [],
                'statistiques': [],
                'prix_carburants': [],
                'actualites_recentes': [],
                'nombre_stations': 0,
                'error_message': "Certaines données ne sont pas disponibles actuellement."
            })

        return context


class ServicesView(DatabaseOptimizedMixin, ListView):
    """Vue optimisée pour la liste des services"""
    model = Service
    template_name = 'bilal/services.html'
    context_object_name = 'services'
    paginate_by = 12

    def get_queryset(self):
        try:
            queryset = Service.objects.select_related().filter(est_actif=True)

            categorie = self.request.GET.get('categorie')
            if categorie and categorie in dict(Service.CATEGORIE_CHOICES):
                queryset = queryset.filter(categorie=categorie)

            return queryset.order_by('ordre', 'nom')

        except Exception as e:
            logger.error(f"Erreur dans ServicesView.get_queryset : {e}")
            return Service.objects.none()

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['categories'] = Service.CATEGORIE_CHOICES
        categorie_selectionnee = self.request.GET.get('categorie', '')
        context['categorie_selectionnee'] = categorie_selectionnee

        # Ajouter le nom de la catégorie sélectionnée
        if categorie_selectionnee:
            for code, nom in Service.CATEGORIE_CHOICES:
                if code == categorie_selectionnee:
                    context['categorie_selectionnee_nom'] = nom
                    break

        return context


class StationsView(DatabaseOptimizedMixin, ListView):
    """Vue optimisée pour la liste des stations"""
    model = Station
    template_name = 'bilal/stations.html'
    context_object_name = 'stations'
    paginate_by = 12

    def get_queryset(self):
        try:
            # Utiliser select_related et prefetch_related pour optimiser
            queryset = Station.objects.select_related().prefetch_related(
                Prefetch('services', queryset=Service.objects.filter(est_actif=True))
            ).filter(est_active=True)

            # Recherche optimisée
            search = self.request.GET.get('q', '').strip()
            if search:
                queryset = queryset.filter(
                    Q(nom__icontains=search) |
                    Q(ville__icontains=search) |
                    Q(region__icontains=search)
                )

            # Filtrage par région
            region = self.request.GET.get('region', '').strip()
            if region:
                queryset = queryset.filter(region=region)

            # Filtrage par ville
            ville = self.request.GET.get('ville', '').strip()
            if ville:
                queryset = queryset.filter(ville=ville)

            return queryset.order_by('ville', 'nom')

        except Exception as e:
            logger.error(f"Erreur dans StationsView.get_queryset : {e}")
            return Station.objects.none()

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

        try:
            # Utiliser des requêtes optimisées pour les listes déroulantes
            context['regions'] = list(Station.objects.filter(
                est_active=True
            ).values_list('region', flat=True).distinct().order_by('region'))

            context['villes'] = list(Station.objects.filter(
                est_active=True
            ).values_list('ville', flat=True).distinct().order_by('ville'))

        except Exception as e:
            logger.error(f"Erreur lors du chargement des filtres : {e}")
            context['regions'] = []
            context['villes'] = []

        context['search_query'] = self.request.GET.get('q', '')
        context['region_selectionnee'] = self.request.GET.get('region', '')
        context['ville_selectionnee'] = self.request.GET.get('ville', '')

        return context


class StationDetailView(DatabaseOptimizedMixin, DetailView):
    """Vue détaillée optimisée d'une station"""
    model = Station
    template_name = 'bilal/station_detail.html'
    context_object_name = 'station'

    def get_object(self, queryset=None):
        try:
            if queryset is None:
                queryset = self.get_queryset()

            # Optimiser avec select_related et prefetch_related
            queryset = queryset.select_related().prefetch_related(
                'services__stations'
            )

            return super().get_object(queryset)

        except Exception as e:
            logger.error(f"Erreur lors du chargement de la station : {e}")
            raise


class ActualitesView(DatabaseOptimizedMixin, ListView):
    """Vue optimisée pour la liste des actualités"""
    model = Actualite
    template_name = 'bilal/actualites.html'
    context_object_name = 'actualites'
    paginate_by = 9

    def get_queryset(self):
        try:
            queryset = Actualite.objects.select_related().filter(
                est_publie=True,
                date_publication__lte=timezone.now()
            )

            type_actu = self.request.GET.get('type', '').strip()
            if type_actu and type_actu in dict(Actualite.TYPE_CHOICES):
                queryset = queryset.filter(type_actualite=type_actu)

            search = self.request.GET.get('q', '').strip()
            if search:
                queryset = queryset.filter(
                    Q(titre__icontains=search) |
                    Q(resume__icontains=search)
                )

            return queryset.order_by('-est_epingle', '-date_publication')

        except Exception as e:
            logger.error(f"Erreur dans ActualitesView.get_queryset : {e}")
            return Actualite.objects.none()

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['types_actualites'] = Actualite.TYPE_CHOICES
        context['type_selectionne'] = self.request.GET.get('type', '')
        context['search_query'] = self.request.GET.get('q', '')

        try:
            context['actualites_epinglees'] = Actualite.objects.filter(
                est_publie=True,
                est_epingle=True,
                date_publication__lte=timezone.now()
            ).order_by('-date_publication')[:3]

        except Exception as e:
            logger.error(f"Erreur lors du chargement des actualités épinglées : {e}")
            context['actualites_epinglees'] = []

        return context


class ActualiteDetailView(DatabaseOptimizedMixin, DetailView):
    """Vue détaillée optimisée d'une actualité"""
    model = Actualite
    template_name = 'bilal/actualite_detail.html'
    context_object_name = 'actualite'
    slug_field = 'slug'

    def get_object(self, queryset=None):
        try:
            obj = super().get_object(queryset)

            # Incrémenter les vues de manière atomique
            with transaction.atomic():
                Actualite.objects.filter(pk=obj.pk).update(vues=obj.vues + 1)
                obj.vues += 1  # Mettre à jour l'objet local

            return obj

        except Exception as e:
            logger.error(f"Erreur lors du chargement de l'actualité : {e}")
            raise

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

        try:
            context['actualites_similaires'] = Actualite.objects.filter(
                est_publie=True,
                type_actualite=self.object.type_actualite,
                date_publication__lte=timezone.now()
            ).exclude(id=self.object.id).order_by('-date_publication')[:3]

        except Exception as e:
            logger.error(f"Erreur lors du chargement des actualités similaires : {e}")
            context['actualites_similaires'] = []

        return context


class PrixCarburantsView(DatabaseOptimizedMixin, TemplateView):
    """Vue optimisée pour afficher les prix des carburants"""
    template_name = 'bilal/prix_carburants.html'

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

        try:
            context['prix_actuels'] = PrixCarburant.objects.filter(
                est_actuel=True
            ).order_by('type_carburant')

            context['historique_prix'] = PrixCarburant.objects.select_related().order_by(
                '-date_application', 'type_carburant'
            )[:20]

        except Exception as e:
            logger.error(f"Erreur lors du chargement des prix : {e}")
            context['prix_actuels'] = []
            context['historique_prix'] = []

        return context


class ContactView(DatabaseOptimizedMixin, TemplateView):
    """Vue optimisée pour la page de contact"""
    template_name = 'bilal/contact.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['form'] = ContactForm()
        return context

    def post(self, request, *args, **kwargs):
        form = ContactForm(request.POST)

        try:
            if form.is_valid():
                with transaction.atomic():
                    form.save()
                messages.success(request, 'Votre message a été envoyé avec succès.')
                return redirect('bilal:contact')

        except Exception as e:
            logger.error(f"Erreur lors de l'envoi du message de contact : {e}")
            messages.error(request, 'Une erreur est survenue. Veuillez réessayer.')

        context = self.get_context_data(**kwargs)
        context['form'] = form
        return render(request, self.template_name, context)