"""
Custom middleware for the Adtlas application.

This module contains custom middleware classes that provide
additional functionality such as request logging, user tracking,
and performance monitoring.

Author: Adtlas Development Team
Project: Adtlas
Version: 1.0.0
"""

import time
import logging
from django.utils.deprecation import MiddlewareMixin
from django.contrib.auth import get_user_model

# Get the logger for this module
logger = logging.getLogger(__name__)

User = get_user_model()


class RequestLoggingMiddleware(MiddlewareMixin):
    """
    Middleware for logging HTTP requests and responses.
    
    This middleware logs information about incoming requests,
    including user information, request method, path, and
    response time for monitoring and debugging purposes.
    """
    
    def process_request(self, request):
        """
        Process the incoming request.
        
        Args:
            request (HttpRequest): The incoming HTTP request
        """
        # Record the start time for performance measurement
        request.start_time = time.time()
        
        # Log basic request information
        user_info = 'Anonymous'
        if hasattr(request, 'user') and request.user.is_authenticated:
            user_info = f"{request.user.email} ({request.user.id})"
        
        logger.info(
            f"Request started: {request.method} {request.path} "
            f"from {self.get_client_ip(request)} by {user_info}"
        )
    
    def process_response(self, request, response):
        """
        Process the outgoing response.
        
        Args:
            request (HttpRequest): The HTTP request
            response (HttpResponse): The HTTP response
            
        Returns:
            HttpResponse: The response object
        """
        # Calculate response time if start_time is available
        if hasattr(request, 'start_time'):
            response_time = time.time() - request.start_time
            
            # Log response information
            logger.info(
                f"Request completed: {request.method} {request.path} "
                f"- Status: {response.status_code} "
                f"- Time: {response_time:.3f}s"
            )
        
        return response
    
    def process_exception(self, request, exception):
        """
        Process exceptions that occur during request handling.
        
        Args:
            request (HttpRequest): The HTTP request
            exception (Exception): The exception that occurred
        """
        # Log exception information
        user_info = 'Anonymous'
        if hasattr(request, 'user') and request.user.is_authenticated:
            user_info = f"{request.user.email} ({request.user.id})"
        
        logger.error(
            f"Request exception: {request.method} {request.path} "
            f"from {self.get_client_ip(request)} by {user_info} "
            f"- Exception: {str(exception)}",
            exc_info=True
        )
    
    def get_client_ip(self, request):
        """
        Get the client's IP address from the request.
        
        Args:
            request (HttpRequest): The HTTP request
            
        Returns:
            str: The client's IP address
        """
        # Check for IP in forwarded headers (for proxy/load balancer setups)
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0].strip()
        else:
            ip = request.META.get('REMOTE_ADDR', 'Unknown')
        
        return ip


class UserActivityMiddleware(MiddlewareMixin):
    """
    Middleware for tracking user activity.
    
    This middleware updates user activity information such as
    last seen timestamp and tracks user sessions for analytics.
    """
    
    def process_request(self, request):
        """
        Process the incoming request to track user activity.
        
        Args:
            request (HttpRequest): The incoming HTTP request
        """
        # Update last activity for authenticated users
        if hasattr(request, 'user') and request.user.is_authenticated:
            try:
                # Update user's last login time periodically
                # This could be optimized to update less frequently
                User.objects.filter(id=request.user.id).update(
                    last_login=time.time()
                )
            except Exception as e:
                # Log error but don't break the request
                logger.warning(f"Failed to update user activity: {str(e)}")


class SecurityHeadersMiddleware(MiddlewareMixin):
    """
    Middleware for adding security headers to responses.
    
    This middleware adds various security headers to HTTP responses
    to improve the security posture of the application.
    """
    
    def process_response(self, request, response):
        """
        Add security headers to the response.
        
        Args:
            request (HttpRequest): The HTTP request
            response (HttpResponse): The HTTP response
            
        Returns:
            HttpResponse: The response with added security headers
        """
        # Add security headers
        response['X-Content-Type-Options'] = 'nosniff'
        response['X-Frame-Options'] = 'DENY'
        response['X-XSS-Protection'] = '1; mode=block'
        response['Referrer-Policy'] = 'strict-origin-when-cross-origin'
        
        # Add Content Security Policy for API endpoints
        if request.path.startswith('/api/'):
            response['Content-Security-Policy'] = (
                "default-src 'self'; "
                "script-src 'self' 'unsafe-inline'; "
                "style-src 'self' 'unsafe-inline'; "
                "img-src 'self' data: https:; "
                "font-src 'self' https:; "
                "connect-src 'self';"
            )
        
        return response


class APIVersionMiddleware(MiddlewareMixin):
    """
    Middleware for handling API versioning.
    
    This middleware processes API version information from headers
    or URL parameters and sets the appropriate version context.
    """
    
    def process_request(self, request):
        """
        Process API version information from the request.
        
        Args:
            request (HttpRequest): The incoming HTTP request
        """
        # Default API version
        api_version = 'v1'
        
        # Check for version in headers
        if 'HTTP_API_VERSION' in request.META:
            api_version = request.META['HTTP_API_VERSION']
        
        # Check for version in Accept header
        accept_header = request.META.get('HTTP_ACCEPT', '')
        if 'application/vnd.tvadspot.' in accept_header:
            try:
                # Extract version from Accept header like:
                # application/vnd.tvadspot.v1+json
                version_part = accept_header.split('vnd.tvadspot.')[1]
                api_version = version_part.split('+')[0]
            except (IndexError, AttributeError):
                pass
        
        # Set the API version in the request
        request.api_version = api_version
        
        # Log API version for debugging
        if request.path.startswith('/api/'):
            logger.debug(f"API request with version: {api_version}")


class CacheControlMiddleware(MiddlewareMixin):
    """
    Middleware for setting cache control headers.
    
    This middleware sets appropriate cache control headers
    based on the type of content being served.
    """
    
    def process_response(self, request, response):
        """
        Set cache control headers based on the response type.
        
        Args:
            request (HttpRequest): The HTTP request
            response (HttpResponse): The HTTP response
            
        Returns:
            HttpResponse: The response with cache control headers
        """
        # Set cache headers for API responses
        if request.path.startswith('/api/'):
            # Most API responses should not be cached
            response['Cache-Control'] = 'no-cache, no-store, must-revalidate'
            response['Pragma'] = 'no-cache'
            response['Expires'] = '0'
        
        # Set cache headers for static content
        elif request.path.startswith('/static/') or request.path.startswith('/media/'):
            # Static content can be cached for longer periods
            response['Cache-Control'] = 'public, max-age=31536000'  # 1 year
        
        return response