"""Request context manager for structured logging.

Provides a context manager that binds request metadata (user, path, method, etc.)
to the structured logger for the duration of request processing.
"""

from typing import Dict, Any
from django.conf import settings
from swifty.utils.mapper import getpath


class RequestContext:
    """Context manager that binds request metadata to a structured logger.

    On enter, extracts configured fields from the request and binds them
    to the logger. On exit, unbinds them to prevent context leakage.

    Default fields extracted:
        - ``user.username`` → ``username``
        - ``user.id`` → ``user_id``
        - ``method`` → ``method``
        - ``path`` → ``path``
        - ``resolver_match.app_name`` → ``app_name``
        - ``resolver_match.url_name`` → ``url_name``

    Custom fields can be configured via ``settings.CONTEXT_FIELDS_MAPPING``.

    Example::

        with RequestContext(logger=self.logger, request_data=request):
            # Logger is now bound with request metadata
            logger.info("Processing request")
    """

    context_fields: tuple = (
        ("user.username", "username"),
        ("user.id", "user_id"),
        ("method", "method"),
        ("resolver_match.app_name", "app_name"),
        ("path", "path"),
        ("resolver_match.url_name", "url_name"),
    )

    def __init__(self, logger: Any, request_data: Dict[str, Any]) -> None:
        """Initialize the request context.

        Args:
            logger: A structlog logger instance supporting bind/unbind.
            request_data: The Django request object or dict-like request data.
        """
        self.logger = logger
        self.request_data = request_data or {}
        self.request_context: Dict[str, Any] = {}

    @property
    def context_fields_mapping(self) -> tuple:
        """Get context fields mapping from settings or use defaults.

        Returns:
            Tuple of (source_path, target_key) pairs.
        """
        return getattr(settings, "CONTEXT_FIELDS_MAPPING", self.context_fields)

    def __enter__(self) -> "RequestContext":
        self.request_context = {
            field[1]: getpath(self.request_data, field[0])
            for field in self.context_fields_mapping
            if getpath(self.request_data, field[0])
        }
        self.logger.bind(**self.request_context)
        return self

    def __exit__(self, *args: Any, **kwargs: Any) -> None:
        self.logger.unbind(*self.request_context.keys())
