"""Loguru configuration helpers for structured logging with indentation"""

# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/02_logger_loguru.ipynb.

# %% ../nbs/02_logger_loguru.ipynb 1
from __future__ import annotations

# %% auto 0
__all__ = ['log_config', 'LogFormatter', 'LogLevelFilter', 'tree_logger', 'setup_logger', 'config_logger']

# %% ../nbs/02_logger_loguru.ipynb
import functools
import sys
from contextlib import contextmanager
from typing import Callable

import fastcore.all as F


# %% ../nbs/02_logger_loguru.ipynb
from loguru import logger
from loguru._logger import Logger


# %% ../nbs/02_logger_loguru.ipynb
class LogFormatter:
    "Formats log records with indentation for tree-structured output"
    _ind_level = 0
    
    def __init__(self) -> None:
        self.padding = 0
        self.indent = '  ' * self._ind_level
        self.fmt = "<g>{level: >7}</> | <d>{extra[indent]}</d><level>{message}</level>\n"

    def format(self, record: dict) -> str:
        "Format record with current indentation level"
        extra = record["extra"]
        if not extra.get('indent', False):  extra['indent'] = ''
        if self.padding:
            length = len("{name}:{function}:{line}".format(**record))
            self.padding = max(self.padding, length)
            record["extra"]["padding"] = " " * (self.padding - length)
        return self.fmt

_formatter = LogFormatter()

# %% ../nbs/02_logger_loguru.ipynb
class LogLevelFilter:
    "Filter log records by minimum level with context manager for temporary override"
    
    def __init__(self, level: int | str): self.level = level
        
    def __call__(self, record: dict) -> bool:
        "Return True if record meets minimum level threshold"
        return record["level"].no >= logger.level(self.level).no  # type: ignore
    
    @contextmanager
    def temp(self, tmp_level: int | str):
        "Temporarily override filter level within context"
        prev_level, self.level = self.level, tmp_level
        try: yield
        finally: self.level = prev_level

_log_level_filter = LogLevelFilter("INFO")

# %% ../nbs/02_logger_loguru.ipynb
log_config = {
    "handlers": [
        {
            "sink": sys.stdout,
            # "sink": sys.stderr,
            "backtrace": not F.IN_NOTEBOOK,
            "level": _log_level_filter.level,
            "filter": _log_level_filter,
            "colorize": True,
            # "format": "<g>{time:HHmmss}</>  | {level} | <level>{message}</level>"
            # "format": "<g>{level: >7}</> | <level>{message}</level>"
            "format": _formatter.format
        },
        # {"sink": "file.log", "serialize": True},
    ],
    # "extra": {"user": "someone"}
}

# %% ../nbs/02_logger_loguru.ipynb
from typing import Any


class tree_logger:
    "Logger wrapper managing hierarchical indentation for tree-structured output"
    
    def __init__(self, logger: Any, fmt: LogFormatter):
        self._fmt = fmt
        self.logger = logger
        
    @property
    def level(self) -> int:
        "Current indentation level (0=root)"
        return self._fmt._ind_level
    
    @property
    def indent(self) -> str:
        "Current indentation string using box drawing chars"
        return '\u2502 ' * self._fmt._ind_level

    def __getattr__(self, name: str) -> Any:
        "Proxy logger methods with indent bound; handle push/pop"
        if name == 'push': return self._push()
        elif name == 'pop': return self._pop()
        return getattr(self.logger.bind(indent=self.indent), name)

    def _push(self) -> Any:
        "Increase indent level, return logger at previous level"
        lg = self.logger.bind(indent=self.indent)
        self._fmt._ind_level += 1
        return lg
        
    def _pop(self) -> Any:
        "Decrease indent level, return logger at new level"
        self._fmt._ind_level -= 1
        return self.logger.bind(indent=self.indent)
    
    def reset(self) -> Any:
        "Reset indentation to root level"
        self._fmt._ind_level = 0
        return self.logger.bind(indent=self.indent)

    @contextmanager
    def inc_indent(self):
        "Context manager temporarily increasing indent by one level"
        self._fmt._ind_level += 1
        yield
        self._fmt._ind_level -= 1

    def bracket_logging(self, header_f: str, *attr_n):
        "Decorator for async methods: log entry with indent, auto-pop on exit"
        llogger = self
        def _wrapper(f: Callable):
            @functools.wraps(f)
            async def _mark_logging_inner(self, *args, **kwargs):
                header = header_f.format(*[
                    attr if type(attr) == str 
                    else getattr(self, str(attr, 'UTF-8')) 
                    for attr in attr_n
                ])
                llogger.push.info(f"{header}: >>>> {f.__name__}...")
                retv = await f(self, *args, **kwargs)
                llogger.pop
                return retv
            return _mark_logging_inner
        return _wrapper

# %% ../nbs/02_logger_loguru.ipynb
def setup_logger(logger, name = '__main__') -> Logger:
    "Apply standard config (format, level filter, backtrace) to logger"
    logger.configure(**log_config)  # type: ignore
    return logger

# %% ../nbs/02_logger_loguru.ipynb
def config_logger(
    logger: Logger  # Logger instance from each module
) -> tuple[Logger, tree_logger]:
    "Configure logger with colors and return (logger, tree_logger) tuple"
    logger = setup_logger(logger)
    logger = logger.opt(colors=True)
    logger.opt = functools.partial(logger.opt, colors=True)
    llogger = tree_logger(logger, _formatter)
    return logger, llogger
