#!/usr/bin/env python3
# coding=utf-8
from __future__ import absolute_import, unicode_literals
import logging
import logging.handlers
from .third_party import logzero
from .mylogger import MultiprocessRotatingFileHandler
import inspect

# 更多logging的level
#   注释掉的是标准level
# CRITICAL = 50
# ERROR = 40
# WARNING = 30
# INFO = 20
VERBOSE = 15
# DEBUG = 10
TRACE = 8
NOISE = 6
LOWEST = 1

FILE_LOG_FORMAT = "%(asctime)s - %(filename)s:%(lineno)s - %(levelno)s %(levelname)s %(pathname)s %(module)s %(funcName)s %(created)f %(thread)d %(threadName)s %(process)d %(name)s - %(message)s"

_level_installed = False


def _install_custom_levels():
    global _level_installed
    if _level_installed:
        return
    logging.addLevelName(VERBOSE, "VERBOSE")
    logging.addLevelName(TRACE, "TRACE")
    logging.addLevelName(NOISE, "NOISE")
    logging.addLevelName(LOWEST, "LOWEST")


def _lower_level(*levels):
    lowest = 0
    for level in levels:
        if not isinstance(level, int):
            level = logging.getLevelName(level)
        if level < lowest:
            lowest = level
    return lowest


def basicConfig(level=logging.INFO, color=False, handler=None, formatter=None,
                logfile=None, file_level=None, maxBytes=0, backupCount=0,
                file_format=FILE_LOG_FORMAT, multi_process=False,
                ):
    _install_custom_levels()
    
    logging._acquireLock()
    try:
        if len(logging.root.handlers) != 0:
            return
        handler = handler or logging.StreamHandler()
        formatter = formatter or logzero.LogFormatter(color=color)
        handler.setFormatter(formatter)
        logging.root.addHandler(handler)
        
        if logfile:
            if multi_process:
                file_handler_class = MultiprocessRotatingFileHandler
            else:
                file_handler_class = logging.handlers.RotatingFileHandler
            file_handler = file_handler_class(logfile, maxBytes=maxBytes, backupCount=backupCount)
            file_formatter = logging.Formatter(file_format)
            file_handler.setFormatter(file_formatter)
            logging.root.addHandler(file_handler)
            
            if file_level is not None:
                file_handler.setLevel(file_level)
                _root_level = _lower_level(level, file_level)
                handler.setLevel(level)
                logging.root.setLevel(_root_level)
        
        if file_level is None:
            logging.root.setLevel(level)
    
    finally:
        logging._releaseLock()


def colorConfig(level=logging.INFO, handler=None, formatter=None, **kwargs):
    basicConfig(level=level, color=True, handler=handler, formatter=formatter, **kwargs)


def _get_outframe_main(frame):
    outframe = frame.f_back
    return outframe.f_globals["__name__"]


def getLogzeroLogger(name=None, logfile=None, level=logging.NOTSET,
                     formatter=None, maxBytes=0, backupCount=0, fileLoglevel=None):
    name = name or _get_outframe_main(inspect.currentframe())
    
    return logzero.setup_logger(
        name=name, logfile=logfile, level=level, formatter=formatter,
        maxBytes=maxBytes, backupCount=backupCount, fileLoglevel=fileLoglevel,
    )


class EnhancedLogger(logging.Logger):
    def verbose(self, msg, *args, **kwargs):
        """高于 DEBUG, 低于 INFO 的级别"""
        if self.isEnabledFor(VERBOSE):
            self._log(VERBOSE, msg, args, **kwargs)
    
    def trace(self, msg, *args, **kwargs):
        """比 DEBUG 低一层的级别"""
        if self.isEnabledFor(TRACE):
            self._log(TRACE, msg, args, **kwargs)
    
    def noise(self, msg, *args, **kwargs):
        """比 DEBUG 低两层的级别"""
        if self.isEnabledFor(NOISE):
            self._log(NOISE, msg, args, **kwargs)
    
    def lowest(self, msg, *args, **kwargs):
        """最低级别的log"""
        if self.isEnabledFor(LOWEST):
            self._log(LOWEST, msg, args, **kwargs)


def getLogger(name=None):
    """

    Args:
        name (str|int): 若不指定则会自动获取

    Returns:
        EnhancedLogger: 比标准logger多了一些级别
        
    :rtype: EnhancedLogger
    """
    name = name or _get_outframe_main(inspect.currentframe())
    
    _old_cls = logging.Logger.manager.loggerClass
    try:
        logging.Logger.manager.loggerClass = EnhancedLogger
        
        logger = logging.getLogger(name)  # type: EnhancedLogger
    finally:
        logging.Logger.manager.loggerClass = _old_cls
    
    return logger  # type: EnhancedLogger