import logging
import threading
from contextlib import contextmanager

_depth_context = threading.local()


def get_depth():
    return getattr(_depth_context, "depth", 0)


def increment_depth():
    _depth_context.depth = get_depth() + 1


def decrement_depth():
    _depth_context.depth = max(0, get_depth() - 1)


@contextmanager
def log_scope(name=None, verbose=False):
    """Context manager to handle indentation and entry/exit logs."""
    if name:
        if verbose:
            debug(f"==> {name}")
        else:
            info(f"==> {name}")

    try:
        increment_depth()
        yield
    finally:
        decrement_depth()


logger = logging.getLogger("vicentin")
logger.addHandler(logging.NullHandler())


def log(msg, level=logging.INFO, s_level=2):
    """Logs a message with the correct indentation based on recursion depth."""
    indent = "\t" * get_depth()
    logger.log(level, f"{indent}{msg}", stacklevel=s_level)


def debug(msg):
    log(msg, logging.DEBUG, s_level=3)


def info(msg):
    log(msg, logging.INFO, s_level=3)


def warn(msg):
    log(msg, logging.WARNING, s_level=3)


def error(msg):
    log(msg, logging.ERROR, s_level=3)


def exception(msg):
    indent = "\t" * get_depth()
    logger.exception(f"{indent}{msg}")


# --- Colorful Formatter ---


class Formatter(logging.Formatter):
    """Refined formatter with a sophisticated color palette for optimization traces."""

    # ANSI Escape Codes (Extended 256-color palette for "prettier" shades)
    GREEN_BOLD = "\033[1;32m"  # Success/Entry points
    BLUE_LIGHT = "\033[38;5;111m"  # Standard Info/Iterations
    GREY_DIM = "\033[38;5;244m"  # Debug/Sub-steps
    YELLOW_SOFT = "\033[38;5;222m"  # Warnings
    RED_SOFT = "\033[38;5;203m"  # Errors
    RESET = "\033[0m"

    TIMESTAMP = f"{GREY_DIM}[%(asctime)s]{RESET} "
    CODE = " {%(filename)s:%(funcName)s:%(lineno)d}"

    # Map levels to colors
    FORMATS = {
        logging.DEBUG: TIMESTAMP + GREY_DIM + "%(message)s" + CODE + RESET,
        logging.INFO: TIMESTAMP + BLUE_LIGHT + "%(message)s" + RESET,
        logging.WARNING: TIMESTAMP + YELLOW_SOFT + "⚠ %(message)s" + RESET,
        logging.ERROR: TIMESTAMP + RED_SOFT + "✖ %(message)s" + RESET,
    }

    def format(self, record):
        # Apply Bold Green specifically to the Dispatcher scopes
        if "==>" in record.msg:
            record.msg = f"{self.GREEN_BOLD}{record.msg}{self.RESET}"

        log_fmt = self.FORMATS.get(record.levelno, self.RESET + "%(message)s")
        formatter = logging.Formatter(log_fmt, datefmt="%H:%M:%S")
        return formatter.format(record)


# --- Library Setup Helper ---


def setup_logging(verbosity_level=2):
    """
    Configures the library-wide logger with the refined Formatter.

    Args:
        verbosity_level (int): An integer mapping to logging levels:
            0: SILENT (Only Errors)
            1: WARNING (Errors and warnings)
            2: INFO (Standard progress logs) [Default]
            3: DEBUG (Detailed internal logs)
    """

    level_map = {
        0: logging.ERROR,
        1: logging.WARNING,
        2: logging.INFO,
        3: logging.DEBUG,
    }

    level = level_map.get(verbosity_level, logging.INFO)

    handler = logging.StreamHandler()
    handler.setFormatter(Formatter())

    if logger.hasHandlers():
        logger.handlers.clear()

    logger.addHandler(handler)
    logger.setLevel(level)
    logger.propagate = False


@contextmanager
def verbosity(level):
    """
    Temporarily changes the library's log level.

    Usage:
        with verbosity(logging.DEBUG):
            model.fit(X, y)
    """
    old_level = logger.getEffectiveLevel()
    logger.setLevel(level)
    try:
        yield
    finally:
        logger.setLevel(old_level)


@contextmanager
def debug_mode():
    """Temporarily enables all internal logs (DEBUG level)."""
    with verbosity(logging.DEBUG):
        yield


@contextmanager
def info_mode():
    """Temporarily enables standard progress logs (INFO level)."""
    with verbosity(logging.INFO):
        yield


@contextmanager
def silent_mode():
    """Temporarily silences all logs except Errors."""
    with verbosity(logging.ERROR):
        yield
