"""
Logging module integration.

Installs a custom ``logging.Handler`` on the root logger and known
framework loggers so that all ``logging.*`` calls are forwarded to
Overcast.
"""

import logging
import traceback

from overcast_sdk.integrations import Integration, DidNotEnable
from overcast_sdk.utils import capture_internal, is_sending


LEVEL_MAP = {
    logging.DEBUG:    "DEBUG",
    logging.INFO:     "INFO",
    logging.WARNING:  "WARNING",
    logging.ERROR:    "ERROR",
    logging.CRITICAL: "ERROR",
}

# Known framework loggers whose ``propagate`` may be False.
_FRAMEWORK_LOGGERS = [
    "uvicorn", "uvicorn.error", "uvicorn.access",
    "gunicorn", "gunicorn.error",
    "django", "flask", "werkzeug",
    "sqlalchemy", "celery",
]


class _OvercastHandler(logging.Handler):
    """Handler that forwards records to the Overcast SDK."""

    def emit(self, record):
        if is_sending():
            return
        with capture_internal:
            self._emit_safe(record)

    def _emit_safe(self, record):
        from overcast_sdk.client import get_client
        from overcast_sdk.scope import get_current_scope
        client = get_client()
        if client is None:
            return

        level = LEVEL_MAP.get(record.levelno, "INFO")
        message = self.format(record)

        meta = {
            "type": "logging",
            "logger_name": record.name,
            "log_level": record.levelname,
            "filename": record.filename,
            "lineno": record.lineno,
            "func_name": record.funcName,
            "module": record.module,
        }

        # Capture exception info
        if record.exc_info and record.exc_info[1]:
            exc = record.exc_info[1]
            tb = "".join(traceback.format_exception(*record.exc_info))
            meta["error"] = {
                "type": type(exc).__name__,
                "message": str(exc),
                "traceback": tb,
            }

        # Breadcrumb
        scope = get_current_scope()
        scope.add_breadcrumb({
            "type": "log",
            "category": record.name,
            "message": message[:256],
            "level": level.lower(),
        })

        client.enqueue(level, message, meta)


class LoggingIntegration(Integration):
    identifier = "logging"

    @staticmethod
    def setup_once():
        handler = _OvercastHandler()
        handler.setLevel(logging.DEBUG)
        fmt = logging.Formatter("%(asctime)s [%(name)s] %(levelname)s: %(message)s")
        handler.setFormatter(fmt)

        logging.root.addHandler(handler)

        for name in _FRAMEWORK_LOGGERS:
            logging.getLogger(name).addHandler(handler)
