"""Structured logging configuration with secrets masking.

Configures ``structlog`` with the :func:`secrets_masking_processor`
from :mod:`cleveragents.shared.redaction` inserted into the processor
chain so that every log event is automatically redacted before
rendering.

Usage::

    from cleveragents.config.logging import configure_structlog, get_logger

    configure_structlog(env="development", log_level="DEBUG")
    logger = get_logger(__name__)
    logger.info("connected", api_key="sk-proj-secret123")
    # api_key will appear as ***REDACTED*** in output
"""

from __future__ import annotations

import logging
from typing import Any

import structlog

from cleveragents.shared.redaction import secrets_masking_processor

__all__ = ["configure_structlog", "get_logger"]


def configure_structlog(
    *,
    env: str = "development",
    log_level: str = "INFO",
) -> None:
    """Configure structlog with secrets masking.

    Args:
        env: Runtime environment name. When ``"production"`` the JSON
            renderer is used; otherwise the coloured console renderer.
        log_level: Minimum log level (e.g. ``"DEBUG"``, ``"INFO"``).

    Raises:
        ValueError: If *log_level* is not a recognised level name.
    """
    numeric_level = getattr(logging, log_level.upper(), None)
    if not isinstance(numeric_level, int):
        raise ValueError(f"Invalid log level: {log_level!r}")

    logging.basicConfig(format="%(message)s", level=numeric_level, force=True)

    renderer: structlog.types.Processor
    if env.lower() == "production":
        renderer = structlog.processors.JSONRenderer()
    else:
        renderer = structlog.dev.ConsoleRenderer()

    shared_processors: list[structlog.types.Processor] = [
        structlog.contextvars.merge_contextvars,
        structlog.stdlib.add_log_level,
        structlog.stdlib.add_logger_name,
        structlog.processors.TimeStamper(fmt="iso"),
        secrets_masking_processor,
        structlog.stdlib.ProcessorFormatter.wrap_for_formatter,
    ]

    structlog.configure(
        processors=shared_processors,
        logger_factory=structlog.stdlib.LoggerFactory(),
        wrapper_class=structlog.stdlib.BoundLogger,
        cache_logger_on_first_use=True,
    )

    formatter = structlog.stdlib.ProcessorFormatter(
        processors=[
            structlog.stdlib.ProcessorFormatter.remove_processors_meta,
            renderer,
        ],
    )

    root_logger = logging.getLogger()
    for handler in root_logger.handlers:
        handler.setFormatter(formatter)


def get_logger(name: str | None = None) -> Any:
    """Return a structlog bound logger.

    Args:
        name: Logger name (typically ``__name__``).

    Returns:
        A structlog ``BoundLogger`` instance.
    """
    return structlog.get_logger(name)
