"""
API Security Middleware
Validates that API requests come from the frontend through nginx reverse proxy
This ensures the API is only accessible from the frontend, not directly from the internet
"""

from django.http import HttpResponseForbidden, JsonResponse
from django.conf import settings
from django.utils.deprecation import MiddlewareMixin
import logging
import re

logger = logging.getLogger('django.security')


class FrontendAPIProxyMiddleware(MiddlewareMixin):
    """
    Enterprise Security: Only allow API requests from frontend through nginx
    
    This middleware validates:
    1. Custom header (X-Internal-API-Key) that nginx adds to prove request came through proxy
    2. Origin/Referer header matches allowed frontend domains
    3. Request comes from internal network (nginx proxy)
    
    In production, this ensures the API cannot be accessed directly from the internet.
    All requests must come through the frontend (nginx reverse proxy).
    """
    
    def __init__(self, get_response):
        self.get_response = get_response
        super().__init__(get_response)
        
        # Get API key from settings (nginx will add this header)
        self.required_api_key = getattr(settings, 'INTERNAL_API_KEY', None)
        
        # Get allowed frontend origins
        self.allowed_origins = getattr(settings, 'CORS_ALLOWED_ORIGINS', [])
        
        # Get allowed referer patterns
        self.allowed_referer_patterns = getattr(settings, 'ALLOWED_REFERER_PATTERNS', [])
        
        # API paths that require validation (default: all /api/ paths)
        self.api_path_pattern = getattr(settings, 'API_SECURITY_PATH_PATTERN', r'^/api/')
        
        # Skip validation in DEBUG mode for development
        self.enforce_in_debug = getattr(settings, 'ENFORCE_API_SECURITY_IN_DEBUG', False)
    
    def process_request(self, request):
        """
        Validate API requests come from frontend through nginx
        """
        # Skip validation for non-API paths
        if not re.match(self.api_path_pattern, request.path):
            return None
        
        # Skip validation in DEBUG mode unless explicitly enabled
        if settings.DEBUG and not self.enforce_in_debug:
            return None
        
        # Skip validation for OPTIONS requests (CORS preflight)
        if request.method == 'OPTIONS':
            return None
        
        # Get the internal API key from header (added by nginx)
        internal_api_key = request.META.get('HTTP_X_INTERNAL_API_KEY', '')
        
        # Validate API key if configured
        if self.required_api_key:
            if internal_api_key != self.required_api_key:
                logger.warning(
                    f"Blocked API request: Missing or invalid X-Internal-API-Key header. "
                    f"Path: {request.path}, IP: {self._get_client_ip(request)}"
                )
                return JsonResponse(
                    {
                        'error': 'Access Denied',
                        'message': 'This API is only accessible through the frontend application.',
                        'code': 'API_ACCESS_DENIED'
                    },
                    status=403
                )
        
        # Validate Origin header (for CORS requests)
        origin = request.META.get('HTTP_ORIGIN', '')
        if origin:
            if origin not in self.allowed_origins:
                logger.warning(
                    f"Blocked API request: Invalid Origin header. "
                    f"Origin: {origin}, Path: {request.path}, IP: {self._get_client_ip(request)}"
                )
                return JsonResponse(
                    {
                        'error': 'Access Denied',
                        'message': 'Invalid origin. This API is only accessible from authorized domains.',
                        'code': 'INVALID_ORIGIN'
                    },
                    status=403
                )
        
        # Validate Referer header (for same-origin requests)
        referer = request.META.get('HTTP_REFERER', '')
        if referer and not origin:  # Only check referer if no origin header
            is_valid_referer = False
            
            # Check against allowed origins
            for allowed_origin in self.allowed_origins:
                if referer.startswith(allowed_origin):
                    is_valid_referer = True
                    break
            
            # Check against referer patterns
            if not is_valid_referer and self.allowed_referer_patterns:
                for pattern in self.allowed_referer_patterns:
                    if re.match(pattern, referer):
                        is_valid_referer = True
                        break
            
            if not is_valid_referer:
                logger.warning(
                    f"Blocked API request: Invalid Referer header. "
                    f"Referer: {referer}, Path: {request.path}, IP: {self._get_client_ip(request)}"
                )
                return JsonResponse(
                    {
                        'error': 'Access Denied',
                        'message': 'Invalid referer. This API is only accessible from authorized domains.',
                        'code': 'INVALID_REFERER'
                    },
                    status=403
                )
        
        # Additional validation: Check if request comes from nginx (internal network)
        # This is a secondary check - the IP whitelist middleware should handle this,
        # but we can add additional validation here if needed
        
        # Request is valid, continue processing
        return None
    
    def _get_client_ip(self, request):
        """Get client IP address from request"""
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            return x_forwarded_for.split(',')[0].strip()
        return request.META.get('REMOTE_ADDR', 'unknown')

