"""Request context middleware — captures client IP and User-Agent per request."""

# Import Awaitable, Callable from collections.abc
from collections.abc import Awaitable, Callable

# Import ContextVar from contextvars
from contextvars import ContextVar

# Import Request from fastapi
from fastapi import Request

# Import BaseHTTPMiddleware from starlette.middleware.base
from starlette.middleware.base import BaseHTTPMiddleware

# Import Response from starlette.responses
from starlette.responses import Response

# Assign request_ip = ContextVar("request_ip", default="")
request_ip: ContextVar[str] = ContextVar("request_ip", default="")
# Assign request_user_agent = ContextVar("request_user_agent", default="")
request_user_agent: ContextVar[str] = ContextVar("request_user_agent", default="")


# Define function resolve_client_ip
def resolve_client_ip(request: Request) -> str:
    """Extract the real client IP, honouring ``X-Forwarded-For`` when present.

    Args:
        request (Request): The incoming Starlette/FastAPI request.

    Returns:
        str: The resolved client IP address, or ``"unknown"`` when unavailable.
    """
    # Assign forwarded = request.headers.get("X-Forwarded-For")
    forwarded = request.headers.get("X-Forwarded-For")
    # Check: forwarded
    if forwarded:
        # Return forwarded.split(",")[0].strip()
        return forwarded.split(",")[0].strip()
    # Check: request.client
    if request.client:
        # Return request.client.host
        return request.client.host
    # Return "unknown"
    return "unknown"


# Define class RequestContextMiddleware
class RequestContextMiddleware(BaseHTTPMiddleware):
    """Middleware that captures client IP and User-Agent into context variables."""

    # Define async function dispatch
    async def dispatch(
        self,
        # Entry: request
        request: Request,
        # Entry: call_next
        call_next: Callable[[Request], Awaitable[Response]],
    ) -> Response:
        """Store client IP and User-Agent in context vars for the current request.

        Args:
            request (Request): The incoming HTTP request.
            call_next (Callable[[Request], Awaitable[Response]]): The next middleware or route handler.

        Returns:
            Response: The HTTP response produced by the downstream handler.
        """
        # Call request_ip.set()
        request_ip.set(resolve_client_ip(request))
        # Call request_user_agent.set()
        request_user_agent.set(request.headers.get("User-Agent", ""))
        # Return await call_next(request)
        return await call_next(request)
