"""Structured logging configuration for the DexFather SDK.

Wraps :mod:`structlog` with sensible defaults.  If *structlog* is not
installed the module silently falls back to the standard library
:mod:`logging` module so that the rest of the SDK remains functional.

Usage::

    from dexfather._logging import get_logger, setup_logging

    setup_logging(level="DEBUG")          # call once at startup
    log = get_logger("dexfather.http")
    log.info("request", method="GET", url="/api/me")
"""

from __future__ import annotations

import logging
import warnings
from typing import Any

try:
    import structlog
    from structlog.stdlib import BoundLogger

    _HAS_STRUCTLOG = True
except ImportError:  # pragma: no cover
    _HAS_STRUCTLOG = False
    BoundLogger = Any  # type: ignore[assignment,misc]


def setup_logging(
    level: str = "INFO",
    json_output: bool = False,
) -> None:
    """Configure structured logging for the SDK.

    Parameters:
        level: Minimum log level (``"DEBUG"``, ``"INFO"``, etc.).
        json_output: When *True*, render log entries as JSON instead of
            the human-readable console format.
    """
    if not _HAS_STRUCTLOG:
        warnings.warn(
            "structlog is not installed — falling back to stdlib logging. "
            "Install it with: pip install structlog",
            stacklevel=2,
        )
        logging.basicConfig(level=getattr(logging, level.upper(), logging.INFO))
        return

    renderer = (
        structlog.dev.ConsoleRenderer()
        if not json_output
        else structlog.processors.JSONRenderer()
    )

    structlog.configure(
        processors=[
            structlog.stdlib.add_log_level,
            structlog.stdlib.add_logger_name,
            structlog.processors.TimeStamper(fmt="iso"),
            structlog.processors.StackInfoRenderer(),
            structlog.processors.format_exc_info,
            renderer,
        ],
        wrapper_class=structlog.stdlib.BoundLogger,
        context_class=dict,
        logger_factory=structlog.PrintLoggerFactory(),
        cache_logger_on_first_use=True,
    )

    # Also set stdlib root logger level so structlog output is not filtered.
    logging.basicConfig(level=getattr(logging, level.upper(), logging.INFO))


def get_logger(name: str) -> BoundLogger:  # type: ignore[type-arg]
    """Return a bound logger for *name*.

    If *structlog* is unavailable a standard :class:`logging.Logger` is
    returned instead.
    """
    if not _HAS_STRUCTLOG:
        return logging.getLogger(name)  # type: ignore[return-value]
    return structlog.get_logger(name)
