import functools
import logging
import warnings

from loguru import logger
import config
from flask import flash, has_request_context

warnings.filterwarnings("ignore", category=UserWarning, module='bs4', message='.*The input looks more like a filename than markup.*')

# todo: the following handler does NOT catch print statements (currently used inside scan2report)


# https://loguru.readthedocs.io/en/stable/overview.html#entirely-compatible-with-standard-logging
class InterceptHandler(logging.Handler):
    def emit(self, record):
        # Get corresponding Loguru level if it exists
        try:
            level = logger.level(record.levelname).name
        except ValueError:
            level = record.levelno

        # Find caller from where originated the logged message
        frame, depth = logging.currentframe(), 2
        while 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())


class FlashLog(object):
    @classmethod
    def info(cls, msg: str):
        cls.log_and_flash_with_level(msg, "info")

    @classmethod
    def warning(cls, msg: str):
        cls.log_and_flash_with_level(msg, "warning")

    @classmethod
    def error(cls, msg: str):
        cls.log_and_flash_with_level(msg, "error")

    @staticmethod
    def flash_loguru_msg(msg: str, loguru_level: str = "info"):
        loguru_to_flask = {'info': 'info', 'warning': 'warning', 'error': 'danger'}
        flask_flash_level = loguru_to_flask.get(loguru_level.lower(), "warning")
        if has_request_context():
            flash(msg, flask_flash_level)

    @classmethod
    def log_and_flash_with_level(cls, msg: str, level: str = "info", depth: int = 2):
        """Levels: info, warning, error"""
        logger.opt(depth=depth).log(level.upper(), msg)
        cls.flash_loguru_msg(msg, level)


if config.LOGGER_INTERCEPT_STD_LOGGING:
    logging.basicConfig(handlers=[InterceptHandler()], level=0)

