"""
Middleware для отслеживания активности пользователей.
Обновляет last_activity при каждом запросе для более точного определения онлайн статуса.
"""

import logging
from django.utils import timezone
from django.core.cache import cache

logger = logging.getLogger(__name__)


class UpdateLastActivityMiddleware:
    """
    Middleware для обновления last_activity пользователя при каждом запросе.
    
    Использует кэширование для уменьшения нагрузки на базу данных:
    - Обновляет last_activity не чаще чем раз в 30 секунд для каждого пользователя
    - Использует Redis cache для хранения времени последнего обновления
    - Исключает статические файлы, media файлы и служебные эндпоинты из отслеживания
    """
    
    # Пути, которые не должны обновлять last_activity
    EXCLUDED_PATHS = [
        '/media/',
        '/static/',
        '/admin/jsi18n/',
        '/api/health/',
        '/api/docs/',
        '/favicon.ico',
        '/robots.txt',
    ]
    
    # HTTP методы, которые должны обновлять last_activity
    INCLUDED_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']
    
    # Интервал обновления в секундах (минимальное время между обновлениями для одного пользователя)
    # Обновляем не чаще чем раз в 30 секунд для баланса между точностью и производительностью
    UPDATE_INTERVAL = 30  # 30 секунд
    
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        # Проверяем, нужно ли обновлять last_activity
        if self.should_update_activity(request):
            self.update_user_activity(request)
        
        response = self.get_response(request)
        return response
    
    def should_update_activity(self, request):
        """
        Проверяет, нужно ли обновлять last_activity для этого запроса.
        """
        # Обновляем только для авторизованных пользователей
        if not request.user.is_authenticated:
            return False
        
        # Проверяем метод запроса
        if request.method not in self.INCLUDED_METHODS:
            return False
        
        # Исключаем определенные пути
        path = request.path
        if any(path.startswith(excluded) for excluded in self.EXCLUDED_PATHS):
            return False
        
        # Проверяем, не обновляли ли мы недавно для этого пользователя
        cache_key = f'user_activity_update:{request.user.id}'
        last_update = cache.get(cache_key)
        
        if last_update:
            # Если прошло меньше UPDATE_INTERVAL секунд, не обновляем
            time_since_update = (timezone.now() - last_update).total_seconds()
            if time_since_update < self.UPDATE_INTERVAL:
                return False
        
        return True
    
    def update_user_activity(self, request):
        """
        Обновляет last_activity для пользователя.
        Использует кэширование для уменьшения нагрузки на базу данных.
        """
        user = request.user
        now = timezone.now()
        
        try:
            cache_key = f'user_activity_update:{user.id}'
            
            # Обновляем last_activity в базе данных
            # Используем update для атомарного обновления без загрузки объекта
            from apps.users.models import User
            User.objects.filter(id=user.id).update(last_activity=now)
            
            # Обновляем кэш для отслеживания последнего обновления
            # Время жизни кэша в 2 раза больше интервала обновления для надежности
            cache.set(cache_key, now, timeout=self.UPDATE_INTERVAL * 2)
            
            # Обновляем объект пользователя в запросе для текущего запроса
            user.last_activity = now
            
            # Учёт дня активности для реферальной программы (не чаще 1 раза в день на пользователя)
            today = now.date()
            day_cache_key = f'referral_activity_day:{user.id}:{today}'
            if not cache.get(day_cache_key):
                try:
                    from apps.referrals.models import UserActivityDay
                    UserActivityDay.objects.get_or_create(user=user, date=today)
                    cache.set(day_cache_key, 1, timeout=86400 * 2)
                except Exception:
                    pass
            
        except Exception as e:
            # Логируем ошибку, но не прерываем выполнение запроса
            logger.error(f"Ошибка при обновлении last_activity для пользователя {user.id}: {e}", exc_info=True)
