"""
Middleware pour gérer les reconnexions automatiques à la base de données MySQL
et éviter l'erreur "MySQL server has gone away"
"""

import logging
from django.db import connection
from django.db.utils import OperationalError
from django.http import Http404
from django.core.exceptions import ImproperlyConfigured

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


class DatabaseReconnectMiddleware:
    """
    Middleware pour gérer automatiquement les reconnexions à la base de données
    en cas de déconnexion inattendue (erreur "server has gone away")
    """

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # Vérifier la connexion avant de traiter la requête
        try:
            self._ensure_connection()
        except Exception as e:
            logger.warning(f"Erreur de connexion à la base de données : {e}")

        response = self.get_response(request)
        return response

    def process_exception(self, request, exception):
        """
        Traiter les exceptions liées à la base de données
        """
        if isinstance(exception, OperationalError):
            error_message = str(exception).lower()

            # Vérifier si c'est une erreur de déconnexion MySQL
            mysql_gone_away_errors = [
                'mysql server has gone away',
                'lost connection to mysql server',
                'can\'t connect to mysql server',
                'the last packet sent successfully',
                'connection was killed'
            ]

            if any(error in error_message for error in mysql_gone_away_errors):
                logger.error(f"Erreur MySQL détectée : {exception}")

                try:
                    # Fermer la connexion existante
                    connection.close()

                    # Tenter une reconnexion
                    self._ensure_connection()

                    logger.info("Reconnexion à MySQL réussie")

                    # Relancer la requête (optionnel)
                    # return self.get_response(request)

                except Exception as reconnect_error:
                    logger.error(f"Échec de la reconnexion : {reconnect_error}")

        # Laisser Django gérer l'exception normalement
        return None

    def _ensure_connection(self):
        """
        S'assurer que la connexion à la base de données est active
        """
        try:
            # Tester la connexion avec une requête simple
            with connection.cursor() as cursor:
                cursor.execute("SELECT 1")

        except OperationalError as e:
            logger.warning(f"Connexion fermée, tentative de reconnexion : {e}")

            # Fermer et rouvrir la connexion
            connection.close()

            # Forcer une nouvelle connexion
            with connection.cursor() as cursor:
                cursor.execute("SELECT 1")

        except Exception as e:
            logger.error(f"Erreur lors de la vérification de la connexion : {e}")
            raise


class DatabaseHealthCheckMiddleware:
    """
    Middleware complémentaire pour surveiller la santé de la base de données
    """

    def __init__(self, get_response):
        self.get_response = get_response
        self.health_check_interval = 100  # Vérifier tous les 100 requêtes
        self.request_count = 0

    def __call__(self, request):
        self.request_count += 1

        # Effectuer une vérification périodique
        if self.request_count % self.health_check_interval == 0:
            self._periodic_health_check()

        response = self.get_response(request)
        return response

    def _periodic_health_check(self):
        """
        Effectuer une vérification périodique de la santé de la base de données
        """
        try:
            with connection.cursor() as cursor:
                cursor.execute("SELECT VERSION()")
                result = cursor.fetchone()
                logger.debug(f"Vérification DB réussie - Version MySQL : {result[0]}")

        except Exception as e:
            logger.warning(f"Échec de la vérification périodique DB : {e}")
            try:
                connection.close()
            except:
                pass