"""Compatibility shim providing keyword-argument logging API on top of stdlib logging.

This module lets the rest of the codebase keep the keyword-argument logging
style (``log.info("event", key=value)``) while using only the Python standard
library ``logging`` module underneath.
"""

from __future__ import annotations

import logging
from typing import Any


class _CompatLogger:
    """Wraps a stdlib :class:`logging.Logger` to accept keyword arguments."""

    def __init__(self, logger: logging.Logger) -> None:
        self._logger = logger

    _STDLIB_LOG_KWARGS = frozenset(("exc_info", "extra", "stack_info", "stacklevel"))

    def _log(self, level: int, event: str, **kwargs: Any) -> None:
        stdlib_kwargs: dict[str, Any] = {}
        for k in self._STDLIB_LOG_KWARGS:
            v = kwargs.pop(k, None)
            if v is not None:
                stdlib_kwargs[k] = v
        if kwargs:
            # Several keys are reserved in LogRecord; rename them to avoid KeyError.
            reserved_renames = {
                "message": "log_message",
                "name": "log_name",
                "filename": "log_filename",
                "funcName": "log_funcName",
                "lineno": "log_lineno",
                "module": "log_module",
                "pathname": "log_pathname",
            }
            for old_key, new_key in reserved_renames.items():
                if old_key in kwargs:
                    kwargs[new_key] = kwargs.pop(old_key)
            stdlib_kwargs["extra"] = kwargs
        self._logger.log(level, event, **stdlib_kwargs)

    def debug(self, event: str, **kwargs: Any) -> None:
        self._log(logging.DEBUG, event, **kwargs)

    def info(self, event: str, **kwargs: Any) -> None:
        self._log(logging.INFO, event, **kwargs)

    def warning(self, event: str, **kwargs: Any) -> None:
        self._log(logging.WARNING, event, **kwargs)

    def warn(self, event: str, **kwargs: Any) -> None:
        self._log(logging.WARNING, event, **kwargs)

    def error(self, event: str, **kwargs: Any) -> None:
        self._log(logging.ERROR, event, **kwargs)

    def critical(self, event: str, **kwargs: Any) -> None:
        self._log(logging.CRITICAL, event, **kwargs)

    def exception(self, event: str, **kwargs: Any) -> None:
        self._log(logging.ERROR, event, exc_info=True, **kwargs)

    def bind(self, **kwargs: Any) -> _CompatLogger:
        """Return a new logger with bound context (no-op for stdlib)."""
        return self


def get_logger(name: str | None = None) -> _CompatLogger:
    """Get a compatibility logger wrapping the stdlib logger for *name*.

    If *name* is ``None`` the caller's module name is used.
    """
    if name is None:
        import sys

        # Walk up the stack to find the caller's module.
        frame = sys._getframe(1)
        module = frame.f_globals.get("__name__", "__main__")
        name = module
    return _CompatLogger(logging.getLogger(name))
