"""
Request Logging Middleware

This middleware logs all HTTP requests and responses.
"""
import time
import logging
from typing import Callable

from fastapi import Request, Response
from starlette.middleware.base import BaseHTTPMiddleware

from api.middleware.correlation import get_correlation_id


logger = logging.getLogger(__name__)


class RequestLoggingMiddleware(BaseHTTPMiddleware):
    """Middleware for logging HTTP requests and responses."""
    
    async def dispatch(
        self, request: Request, call_next: Callable[[Request], Response]
    ) -> Response:
        """
        Process request and log details.
        
        Args:
            request: The incoming request
            call_next: The next middleware/handler
            
        Returns:
            The response
        """
        # Start timing
        start_time = time.time()
        
        # Extract request info
        correlation_id = get_correlation_id()
        method = request.method
        url = str(request.url)
        client_ip = request.client.host if request.client else "unknown"
        user_agent = request.headers.get("User-Agent", "unknown")
        
        # Log request
        logger.info(
            "Request started",
            extra={
                "correlation_id": correlation_id,
                "method": method,
                "url": url,
                "client_ip": client_ip,
                "user_agent": user_agent,
            }
        )
        
        # Process request
        try:
            response = await call_next(request)
        except Exception as e:
            # Calculate duration
            duration = time.time() - start_time
            
            # Log error
            logger.error(
                "Request failed",
                extra={
                    "correlation_id": correlation_id,
                    "method": method,
                    "url": url,
                    "duration": f"{duration:.3f}s",
                    "error": str(e),
                },
                exc_info=True
            )
            raise
        
        # Calculate duration
        duration = time.time() - start_time
        
        # Log response
        logger.info(
            "Request completed",
            extra={
                "correlation_id": correlation_id,
                "method": method,
                "url": url,
                "status_code": response.status_code,
                "duration": f"{duration:.3f}s",
            }
        )
        
        return response