import os
import sys
import logging
import warnings
from typing import Callable

from nest.settings import settings


class ExceptionFilter(logging.Filter):
    """Avoid showing exceptions twice.
    """

    def filter(self, record: object) -> bool:
        return record.levelno != logging.ERROR


def setup_logger() -> logging.RootLogger:
    """Initialize logger.

    Returns:
        The global logger
    """

    # set up logger
    logger = logging.getLogger('Nest')
    logger.setLevel(logging.DEBUG)
    # create a formatter and add it to the handlers
    screen_formatter = logging.Formatter('%(message)s')
    # create a console handler
    screen_handler = logging.StreamHandler()
    screen_handler.setLevel(logging.INFO)
    screen_handler.setFormatter(screen_formatter)
    screen_handler.addFilter(ExceptionFilter())
    logger.addHandler(screen_handler)
    if settings['LOGGING_TO_FILE']:
        # create a file handler which logs warning and error messages
        file_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
        file_handler = logging.FileHandler(settings['LOGGING_PATH'], encoding='utf8')
        file_handler.setLevel(logging.WARNING)
        file_handler.setFormatter(file_formatter)
        logger.addHandler(file_handler)

    return logger


def exception(func: Callable) -> Callable:
    """Decorator for logging errors and warnings of function.

    Parameters:
        func:
            The decorated function
    """

    def wrapper(*args, **kwargs):
        try:
            with warnings.catch_warnings(record=True) as warning_list:
                warnings.simplefilter('always')
                res = func(*args, **kwargs)
                for w in warning_list:
                    logger.warning(w.message)
            return res
        except Exception as exc_info:
            logger.exception(exc_info)
            raise

    return wrapper


# create global logger
logger = setup_logger()