import logging
import sys

from .config import LOG_COLORS, color_to_ansi

# Custom log level values
SUCCESS_LEVEL = 25
STARTUP_LEVEL = 15
VALIDATION_LEVEL = 21
DRY_RUN_LEVEL = 16

# Register custom levels
logging.addLevelName(SUCCESS_LEVEL, "SUCCESS")
logging.addLevelName(STARTUP_LEVEL, "STARTUP")
logging.addLevelName(VALIDATION_LEVEL, "VALIDATION")
logging.addLevelName(DRY_RUN_LEVEL, "DRY_RUN")

# Derived from LOG_COLORS — single source of truth, stays in sync automatically
HINT_COLORS = {level: color_to_ansi(color) for level, color in LOG_COLORS.items()}
RESET_COLOR = "\033[0m"

# Guard: prevent register_custom_levels() from patching twice if module is reloaded
_registered = False


def _print_hint(level_name: str, hint: str, logger=None) -> None:
    """Prints a hint line below the log message with matching color."""
    custom = getattr(logger, "_custom_colors", {})
    color = color_to_ansi(custom[level_name]) if level_name in custom else HINT_COLORS.get(level_name, "")
    line = f"{color}                                 \u2514\u2500 {hint}{RESET_COLOR}"
    try:
        print(line, file=sys.stdout)
    except UnicodeEncodeError:
        print(line.encode("ascii", errors="replace").decode("ascii"), file=sys.stdout)


def _format_with_border(message: str, border: bool = True) -> str:
    """Formats message with # border if border is True."""
    if border:
        return f"{'#' * 10} {message} {'#' * 10}"
    return message


# Custom log methods
def success(self, message, *args, **kwargs):
    hint = kwargs.pop("hint", None)
    if self.isEnabledFor(SUCCESS_LEVEL):
        self._log(SUCCESS_LEVEL, message, args, **kwargs)
        if hint:
            _print_hint("SUCCESS", hint, self)


def startup(self, message, *args, **kwargs):
    hint = kwargs.pop("hint", None)
    border = kwargs.pop("border", True)
    if self.isEnabledFor(STARTUP_LEVEL):
        self._log(STARTUP_LEVEL, _format_with_border(message, border), args, **kwargs)
        if hint:
            _print_hint("STARTUP", hint, self)


def finished(self, message, *args, **kwargs):
    hint = kwargs.pop("hint", None)
    border = kwargs.pop("border", True)
    if self.isEnabledFor(SUCCESS_LEVEL):
        self._log(SUCCESS_LEVEL, _format_with_border(message, border), args, **kwargs)
        if hint:
            _print_hint("SUCCESS", hint, self)


def validation(self, message, *args, **kwargs):
    hint = kwargs.pop("hint", None)
    if self.isEnabledFor(VALIDATION_LEVEL):
        self._log(VALIDATION_LEVEL, message, args, **kwargs)
        if hint:
            _print_hint("VALIDATION", hint, self)


def dry_run(self, message, *args, **kwargs):
    hint = kwargs.pop("hint", None)
    if self.isEnabledFor(DRY_RUN_LEVEL):
        self._log(DRY_RUN_LEVEL, message, args, **kwargs)
        if hint:
            _print_hint("DRY_RUN", hint, self)


# Standard methods wrapped with hint support
def _debug_with_hint(self, message, *args, **kwargs):
    hint = kwargs.pop("hint", None)
    if self.isEnabledFor(logging.DEBUG):
        self._log(logging.DEBUG, message, args, **kwargs)
        if hint:
            _print_hint("DEBUG", hint, self)


def _info_with_hint(self, message, *args, **kwargs):
    hint = kwargs.pop("hint", None)
    if self.isEnabledFor(logging.INFO):
        self._log(logging.INFO, message, args, **kwargs)
        if hint:
            _print_hint("INFO", hint, self)


def _warning_with_hint(self, message, *args, **kwargs):
    hint = kwargs.pop("hint", None)
    if self.isEnabledFor(logging.WARNING):
        self._log(logging.WARNING, message, args, **kwargs)
        if hint:
            _print_hint("WARNING", hint, self)


def _error_with_hint(self, message, *args, **kwargs):
    hint = kwargs.pop("hint", None)
    if self.isEnabledFor(logging.ERROR):
        self._log(logging.ERROR, message, args, **kwargs)
        if hint:
            _print_hint("ERROR", hint, self)


def _critical_with_hint(self, message, *args, **kwargs):
    hint = kwargs.pop("hint", None)
    if self.isEnabledFor(logging.CRITICAL):
        self._log(logging.CRITICAL, message, args, **kwargs)
        if hint:
            _print_hint("CRITICAL", hint, self)


def register_custom_levels() -> None:
    """
    Binds custom logging methods to the Logger class.
    Safe to call multiple times — patches are applied only once.
    """
    global _registered
    if _registered:
        return

    logging.Logger.success = success
    logging.Logger.startup = startup
    logging.Logger.finished = finished
    logging.Logger.validation = validation
    logging.Logger.dry_run = dry_run

    logging.Logger.debug = _debug_with_hint
    logging.Logger.info = _info_with_hint
    logging.Logger.warning = _warning_with_hint
    logging.Logger.error = _error_with_hint
    logging.Logger.critical = _critical_with_hint

    _registered = True
