"""
Rate limiting middleware using Redis for distributed rate limiting.
"""
from fastapi import Request, HTTPException
from starlette.middleware.base import BaseHTTPMiddleware
from app.core.redis import redis_client
import time
import structlog

logger = structlog.get_logger(__name__)

class RateLimitMiddleware(BaseHTTPMiddleware):
    """
    Redis-backed rate limiter.
    Supports different limits per route/user.
    """
    
    def __init__(self, app, requests_per_minute: int = 60):
        super().__init__(app)
        self.requests_per_minute = requests_per_minute
        self.window_seconds = 60
        
    async def dispatch(self, request: Request, call_next):
        # Skip rate limiting for health checks
        if request.url.path in ["/", "/api/v1/health"]:
            return await call_next(request)
            
        # Get identifier (IP or user)
        identifier = self._get_identifier(request)
        key = f"ratelimit:{identifier}"
        
        # Check rate limit
        try:
            current_count = await redis_client.client.get(key)
            
            if current_count is None:
                # First request in window
                await redis_client.client.setex(key, self.window_seconds, 1)
            else:
                current_count = int(current_count)
                if current_count >= self.requests_per_minute:
                    logger.warning("rate_limit_exceeded", identifier=identifier, count=current_count)
                    raise HTTPException(
                        status_code=429,
                        detail="Rate limit exceeded. Please try again later.",
                        headers={"Retry-After": "60"}
                    )
                # Increment counter
                await redis_client.client.incr(key)
                
        except HTTPException:
            raise
        except Exception as e:
            # If Redis is down, log but don't block requests
            logger.error("rate_limit_check_failed", error=str(e))
            
        response = await call_next(request)
        return response
        
    def _get_identifier(self, request: Request) -> str:
        """Get unique identifier for rate limiting."""
        # Try to get authenticated user first
        auth_header = request.headers.get("authorization", "")
        if auth_header.startswith("Bearer "):
            return f"user:{auth_header[7:20]}"  # Use token prefix
            
        # Fall back to IP address
        forwarded = request.headers.get("x-forwarded-for")
        if forwarded:
            return f"ip:{forwarded.split(',')[0]}"
        return f"ip:{request.client.host}"
