import logging
import re
import sys

from loguru import logger

from app.config import settings

LEVEL_ICONS = {
    "TRACE": "[~]",
    "DEBUG": "[.]",
    "INFO": "[i]",
    "SUCCESS": "[+]",
    "WARNING": "[!]",
    "ERROR": "[e]",
    "CRITICAL": "[e]",
}

LEVEL_COLORS = {
    "TRACE": "\033[35m",
    "DEBUG": "\033[37m",
    "INFO": "\033[34m",
    "SUCCESS": "\033[32m",
    "WARNING": "\033[33m",
    "ERROR": "\033[31m",
    "CRITICAL": "\033[31m",
}
RESET = "\033[0m"


def _loguru_fmt(record) -> str:  # type: ignore[override]
    level = record["level"].name
    icon = LEVEL_ICONS.get(level, "[i]")
    color = LEVEL_COLORS.get(level, "")
    ts = record["time"].strftime("%H:%M:%S")
    msg = record["message"].replace("<", "\\<").replace("{", "{{").replace("}", "}}")
    return f"{RESET}[{ts}] {color}{icon}{RESET} {msg}\n"


class _UvicornInterceptHandler(logging.Handler):
    """Route all standard logging records (uvicorn, fastapi) into loguru."""

    def emit(self, record: logging.LogRecord) -> None:
        try:
            level = logger.level(record.levelname).name
        except ValueError:
            level = record.levelno

        frame, depth = sys._getframe(6), 6
        while frame and frame.f_code.co_filename == logging.__file__:
            frame = frame.f_back
            depth += 1

        logger.opt(depth=depth, exception=record.exc_info).log(
            level, record.getMessage()
        )


_logging_configured = False


def setup_logging() -> None:
    global _logging_configured
    if _logging_configured:
        return
    _logging_configured = True

    logger.remove()

    logger.add(
        sys.stderr,
        format=_loguru_fmt,
        level="DEBUG" if settings.debug else "INFO",
        colorize=False,
    )

    settings.logs_dir.mkdir(parents=True, exist_ok=True)

    def _file_fmt(record) -> str:  # type: ignore[override]
        level = record["level"].name
        icon = LEVEL_ICONS.get(level, "[i]")
        ts = record["time"].strftime("%Y-%m-%d %H:%M:%S")
        msg = (
            record["message"].replace("<", "\\<").replace("{", "{{").replace("}", "}}")
        )
        return f"[{ts}] {icon} {msg}\n"

    logger.add(
        settings.logs_dir / "steampanel_{time:YYYY-MM-DD}.log",
        format=_file_fmt,
        level="DEBUG",
        rotation="1 day",
        retention="7 days",
        compression="zip",
    )

    _install_intercept()


class _AioSQLiteFilter(logging.Filter):
    """Reformats raw aiosqlite debug messages into readable DB operation lines."""

    _OP_RE = re.compile(r"method (\w+) of sqlite3\.(\w+)")
    _SQL_RE = re.compile(r',\s*"(.*?)"(?:,\s*(\(.*?\)))?\s*\)$', re.DOTALL)

    def filter(self, record: logging.LogRecord) -> bool:
        msg = record.getMessage()
        # Drop the redundant "operation X completed" lines
        if " completed" in msg:
            return False
        if msg.startswith("executing"):
            op_m = self._OP_RE.search(msg)
            method = op_m.group(1).upper() if op_m else "OP"
            sql_m = self._SQL_RE.search(msg)
            if sql_m:
                sql = sql_m.group(1).strip()
                params = sql_m.group(2) or ""
                record.msg = f"[DB] {sql}" + (f"  {params}" if params else "")
            else:
                record.msg = f"[DB] {method}"
            record.args = ()
        return True


def _install_intercept() -> None:
    intercept = _UvicornInterceptHandler()
    for name in ("", "uvicorn", "uvicorn.error", "uvicorn.access", "fastapi"):
        log = logging.getLogger(name)
        log.handlers = [intercept]
        log.setLevel(logging.DEBUG)
        log.propagate = False

    # Format aiosqlite SQL logs instead of silencing them
    aiosqlite_log = logging.getLogger("aiosqlite")
    aiosqlite_log.setLevel(logging.DEBUG)
    aiosqlite_log.addFilter(_AioSQLiteFilter())

    logging.getLogger("asyncio").setLevel(logging.WARNING)
