"""
Django authentication signals for systematic user activity tracking.

This module uses Django's built-in authentication signals to automatically
track user activity for both web (session) and API (JWT) authentication.
"""

import logging
from django.dispatch import receiver, Signal
from django.contrib.auth.signals import user_logged_in, user_logged_out, user_login_failed
from django.contrib.auth import get_user_model
from django.core.cache import cache
from django.utils import timezone

logger = logging.getLogger(__name__)
User = get_user_model()

# Custom signal for JWT authentication
jwt_authenticated = Signal()


@receiver(user_logged_in)
def track_user_login_activity(sender, request, user, **kwargs):
    """
    Track user activity when user logs in via web interface.
    
    This signal is automatically fired by Django when a user logs in
    using the django.contrib.auth.login() function.
    """
    _update_user_activity(user, 'web_login')
    logger.info(f"User {user.pk} logged in via web interface")


@receiver(user_logged_out)
def track_user_logout_activity(sender, request, user, **kwargs):
    """
    Track user activity when user logs out via web interface.
    
    Note: We still update activity on logout to show the user was active
    at logout time.
    """
    if user and user.is_authenticated:
        _update_user_activity(user, 'web_logout')
        logger.info(f"User {user.pk} logged out via web interface")


@receiver(user_login_failed)
def track_failed_login_attempts(sender, credentials, request, **kwargs):
    """
    Track failed login attempts.
    
    Note: This doesn't update last_active_date since login failed,
    but could be used for security monitoring.
    """
    username = credentials.get('username', 'unknown')
    logger.warning(f"Failed login attempt for username: {username}")


@receiver(jwt_authenticated)
def track_jwt_authentication_activity(sender, user, request, **kwargs):
    """
    Track user activity when JWT token is validated.
    
    This custom signal should be fired whenever a JWT token is successfully
    validated in the authentication process.
    """
    _update_user_activity(user, 'jwt_auth')
    logger.debug(f"User {user.pk} authenticated via JWT")


def _update_user_activity(user, activity_type):
    """
    Update user's last active date with intelligent caching.
    
    Uses cache to avoid updating the database on every request.
    Only updates if the last update was more than 5 minutes ago.
    
    Args:
        user: User instance
        activity_type: Type of activity ('web_login', 'web_logout', 'jwt_auth')
    """
    try:
        cache_key = f"user_activity_{user.pk}"
        cache_timeout = 300  # 5 minutes
        
        last_update = cache.get(cache_key)
        now = timezone.now()
        
        # If no cache entry or cache expired, update the database
        if last_update is None:
            # Use update() to avoid triggering signals and reduce overhead
            User.objects.filter(pk=user.pk).update(last_active_date=now)
            
            # Cache the update time
            cache.set(cache_key, now, cache_timeout)
            
            logger.debug(f"Updated last_active_date for user {user.pk} via {activity_type}")
            
    except Exception as e:
        # Log the error but don't break the authentication process
        logger.error(f"Error updating user activity for user {user.pk}: {str(e)}")


def fire_jwt_authenticated_signal(user, request):
    """
    Helper function to manually fire the JWT authentication signal.
    
    This should be called from JWT authentication backends when a user
    is successfully authenticated via JWT token.
    
    Args:
        user: User instance that was authenticated
        request: Request object
    """
    jwt_authenticated.send(
        sender=fire_jwt_authenticated_signal,
        user=user,
        request=request
    ) 