# This file was auto-generated by Fern from our API Definition.

import logging
import typing

LogLevel = typing.Literal["debug", "info", "warn", "error"]

_LOG_LEVEL_MAP: typing.Dict[LogLevel, int] = {
    "debug": 1,
    "info": 2,
    "warn": 3,
    "error": 4,
}


class ILogger(typing.Protocol):
    def debug(self, message: str, **kwargs: typing.Any) -> None: ...
    def info(self, message: str, **kwargs: typing.Any) -> None: ...
    def warn(self, message: str, **kwargs: typing.Any) -> None: ...
    def error(self, message: str, **kwargs: typing.Any) -> None: ...


class ConsoleLogger:
    _logger: logging.Logger

    def __init__(self) -> None:
        self._logger = logging.getLogger("fern")
        if not self._logger.handlers:
            handler = logging.StreamHandler()
            handler.setFormatter(logging.Formatter("%(levelname)s - %(message)s"))
            self._logger.addHandler(handler)
            self._logger.setLevel(logging.DEBUG)

    def debug(self, message: str, **kwargs: typing.Any) -> None:
        self._logger.debug(message, extra=kwargs)

    def info(self, message: str, **kwargs: typing.Any) -> None:
        self._logger.info(message, extra=kwargs)

    def warn(self, message: str, **kwargs: typing.Any) -> None:
        self._logger.warning(message, extra=kwargs)

    def error(self, message: str, **kwargs: typing.Any) -> None:
        self._logger.error(message, extra=kwargs)


class LogConfig(typing.TypedDict, total=False):
    level: LogLevel
    logger: ILogger
    silent: bool


class Logger:
    _level: int
    _logger: ILogger
    _silent: bool

    def __init__(self, *, level: LogLevel, logger: ILogger, silent: bool) -> None:
        self._level = _LOG_LEVEL_MAP[level]
        self._logger = logger
        self._silent = silent

    def _should_log(self, level: LogLevel) -> bool:
        return not self._silent and self._level <= _LOG_LEVEL_MAP[level]

    def is_debug(self) -> bool:
        return self._should_log("debug")

    def is_info(self) -> bool:
        return self._should_log("info")

    def is_warn(self) -> bool:
        return self._should_log("warn")

    def is_error(self) -> bool:
        return self._should_log("error")

    def debug(self, message: str, **kwargs: typing.Any) -> None:
        if self.is_debug():
            self._logger.debug(message, **kwargs)

    def info(self, message: str, **kwargs: typing.Any) -> None:
        if self.is_info():
            self._logger.info(message, **kwargs)

    def warn(self, message: str, **kwargs: typing.Any) -> None:
        if self.is_warn():
            self._logger.warn(message, **kwargs)

    def error(self, message: str, **kwargs: typing.Any) -> None:
        if self.is_error():
            self._logger.error(message, **kwargs)


_default_logger: Logger = Logger(level="info", logger=ConsoleLogger(), silent=True)


def create_logger(config: typing.Optional[typing.Union[LogConfig, Logger]] = None) -> Logger:
    if config is None:
        return _default_logger
    if isinstance(config, Logger):
        return config
    return Logger(
        level=config.get("level", "info"),
        logger=config.get("logger", ConsoleLogger()),
        silent=config.get("silent", True),
    )
