"""
Custom middleware for API rate limiting and logging.
"""
import time
import json
from django.utils.deprecation import MiddlewareMixin
from django.core.cache import cache
from django.http import JsonResponse
from django.conf import settings
from .models import APIUsage, AuditLog
from django.contrib.auth import get_user_model

User = get_user_model()


class APIRateLimitMiddleware(MiddlewareMixin):
    """
    Rate limiting middleware for API endpoints.
    """
    
    def process_request(self, request):
        # Only apply to API endpoints
        if not request.path.startswith('/api/'):
            return None
            
        # Skip rate limiting for admin users
        if request.user.is_authenticated and request.user.is_staff:
            return None
            
        # Get user (from JWT or API key)
        user = getattr(request, 'user', None)
        if not user or not user.is_authenticated:
            return None
            
        # Get rate limits for user's subscription
        subscription_type = getattr(user, 'subscription_type', 'free')
        rate_limits = self.get_rate_limits(subscription_type)
        
        if not rate_limits:
            return None
            
        # Check rate limits
        if not self.check_rate_limit(user, request, rate_limits):
            return JsonResponse({
                'error': 'Rate limit exceeded',
                'message': 'Too many requests. Please try again later.',
                'retry_after': 60
            }, status=429)
            
        return None
    
    def get_rate_limits(self, subscription_type):
        """Get rate limits for subscription type."""
        try:
            from .models import APIRateLimit
            rate_limit = APIRateLimit.objects.get(subscription_type=subscription_type)
            return {
                'per_minute': rate_limit.requests_per_minute,
                'per_hour': rate_limit.requests_per_hour,
                'per_day': rate_limit.requests_per_day,
            }
        except:
            # Default limits if not configured
            return {
                'per_minute': 60,
                'per_hour': 1000,
                'per_day': 10000,
            }
    
    def check_rate_limit(self, user, request, limits):
        """Check if request is within rate limits."""
        now = int(time.time())
        user_id = str(user.id)
        
        # Check per-minute limit
        minute_key = f'rate_limit:{user_id}:{now // 60}'
        minute_count = cache.get(minute_key, 0)
        if minute_count >= limits['per_minute']:
            return False
        cache.set(minute_key, minute_count + 1, 60)
        
        # Check per-hour limit
        hour_key = f'rate_limit:{user_id}:{now // 3600}'
        hour_count = cache.get(hour_key, 0)
        if hour_count >= limits['per_hour']:
            return False
        cache.set(hour_key, hour_count + 1, 3600)
        
        # Check per-day limit
        day_key = f'rate_limit:{user_id}:{now // 86400}'
        day_count = cache.get(day_key, 0)
        if day_count >= limits['per_day']:
            return False
        cache.set(day_key, day_count + 1, 86400)
        
        return True


class APILoggingMiddleware(MiddlewareMixin):
    """
    Logging middleware for API requests.
    """
    
    def process_request(self, request):
        request.start_time = time.time()
        return None
    
    def process_response(self, request, response):
        # Only log API endpoints
        if not request.path.startswith('/api/'):
            return response
            
        # Skip logging for certain endpoints
        skip_paths = ['/api/schema/', '/api/docs/', '/api/redoc/']
        if any(request.path.startswith(path) for path in skip_paths):
            return response
            
        # Calculate response time
        if hasattr(request, 'start_time'):
            response_time = int((time.time() - request.start_time) * 1000)
        else:
            response_time = 0
            
        # Get user
        user = getattr(request, 'user', None)
        if not user or not user.is_authenticated:
            return response
            
        # Log API usage
        try:
            APIUsage.objects.create(
                user=user,
                endpoint=request.path,
                method=request.method,
                status_code=response.status_code,
                response_time_ms=response_time,
                ip_address=self.get_client_ip(request),
                user_agent=request.META.get('HTTP_USER_AGENT', '')[:500]
            )
        except Exception as e:
            # Log error but don't break the request
            import logging
            logger = logging.getLogger(__name__)
            logger.error(f"Failed to log API usage: {e}")
            
        return response
    
    def get_client_ip(self, request):
        """Get client IP address."""
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip


class AuditLoggingMiddleware(MiddlewareMixin):
    """
    Audit logging middleware for security and compliance.
    """
    
    def process_request(self, request):
        # Only log authenticated requests
        if not hasattr(request, 'user') or not request.user.is_authenticated:
            return None
            
        # Track sensitive actions
        sensitive_actions = [
            'POST', 'PUT', 'PATCH', 'DELETE'
        ]
        
        if request.method in sensitive_actions:
            try:
                AuditLog.objects.create(
                    user=request.user,
                    action=f'{request.method} {request.path}',
                    resource_type='api_request',
                    details={
                        'method': request.method,
                        'path': request.path,
                        'query_params': dict(request.GET),
                        'content_type': request.content_type,
                    },
                    ip_address=self.get_client_ip(request),
                    user_agent=request.META.get('HTTP_USER_AGENT', '')[:500]
                )
            except Exception as e:
                # Log error but don't break the request
                import logging
                logger = logging.getLogger(__name__)
                logger.error(f"Failed to create audit log: {e}")
                
        return None
    
    def get_client_ip(self, request):
        """Get client IP address."""
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip

