"""Request-scoped ContextVars that propagate into log records.

The server sets these at entry points (Telegram webhook, scheduler dispatch,
REST call) and they propagate through async calls automatically. A
``LogRecordFactory`` installed by ``notify_bridge_server.logging_setup``
reads them so every log line is tagged (``request_id``, ``command``,
``chat_id``, ``bot_id``, ``dispatch_id``) without each call site having
to pass the values explicitly.

Kept in ``notify_bridge_core`` so core modules (``TelegramClient``,
``NotificationDispatcher``) can *set* additional context (e.g. a
``dispatch_id``) without depending on the server package.
"""

from __future__ import annotations

from contextlib import contextmanager
from contextvars import ContextVar, Token
from typing import Any, Iterator

request_id_var: ContextVar[str | None] = ContextVar("request_id", default=None)
command_var: ContextVar[str | None] = ContextVar("command", default=None)
chat_id_var: ContextVar[str | None] = ContextVar("chat_id", default=None)
bot_id_var: ContextVar[int | None] = ContextVar("bot_id", default=None)
dispatch_id_var: ContextVar[str | None] = ContextVar("dispatch_id", default=None)

_VAR_MAP: dict[str, ContextVar[Any]] = {
    "request_id": request_id_var,
    "command": command_var,
    "chat_id": chat_id_var,
    "bot_id": bot_id_var,
    "dispatch_id": dispatch_id_var,
}


@contextmanager
def bind_log_context(**kwargs: Any) -> Iterator[None]:
    """Bind the given context fields for the duration of the ``with`` block.

    Unknown keys are ignored so callers can pass whatever they want without
    an ``if`` ladder. Values are reset on exit even if the block raises.

    Example:
        ``with bind_log_context(request_id="abc", command="random"): ...``
    """
    tokens: list[tuple[ContextVar[Any], Token]] = []
    try:
        for key, value in kwargs.items():
            var = _VAR_MAP.get(key)
            if var is None:
                continue
            tokens.append((var, var.set(value)))
        yield
    finally:
        for var, tok in tokens:
            var.reset(tok)


def current_log_context() -> dict[str, Any]:
    """Return a snapshot of the currently-bound context values (non-None)."""
    snap: dict[str, Any] = {}
    for key, var in _VAR_MAP.items():
        val = var.get()
        if val is not None:
            snap[key] = val
    return snap
