#!/usr/bin/env python
# -*-coding: utf-8 -*-
"""
author  : Chen XuHui
data    : 2023/10/9
file    : get_logger.py
name    : get_logger
doc     : 核心是get_debug_logger()函数.
开发过程中, 时常需要我们打印一些数据或信息来帮助我们判断代码
是否正常工作, 但print()函数的使用让取消打印变得麻烦,
因此我们考虑使用logging来实现开发dubug过程中的信息打印过程,
通过setLevel()函数, 将level级别提高, 就可以取消低级别的打印消息.

本文件中的 get_debug_logger()函数 可以快速生成一个logger对象,
以帮助在开发过程中的debug过程, 另外由于使用了colorlog模块,
对日志输出进行了颜色控制, 不再需要面对满屏的红色.
"""
import inspect
import logging
import os
import sys

from corekit.utils.path import WORK_DIR

# 参数传入的优先级 > 顶层控制优先级
top_log_level_control = {
    # 'kz_rule.py': 30,  # 是否展示结果的原因
}  # 顶层控制等级, 当log_level缺省时, 采用此处的log等级设置, 无设置时默认为logging.DEBUG


def getmessage(self, sep_symbol=', '):
    msg = str(self.msg)
    for arg in self.args:
        msg += sep_symbol + str(arg)
    return msg


logging.LogRecord.getMessage = getmessage  # 解决日志对象无法处理多个输入的情况, 比如_logger.warning(1, 2, 3)时会报错


def get_debug_logger(
    log_name: str = None,
    *,
    log_level: int = None,
    formatter: str = None,
    datefmt: int = None,
    filename: str = None,
) -> logging.Logger:
    """
    生成日志对象logger, 帮助开发过程中控制台的调试
    :param log_name: str, 日志名, 默认为 f'{__name__}.py'
    :param log_level: 日志级别
    :param formatter: log格式控制
    :param datefmt: 时间格式
    :param filename: 日志文件名
    :return: logger对象
    """
    try:
        import colorlog
    except ImportError:
        # print(
        #     f'没有<colorlog>模块, 无法使用彩色日志功能\n'
        #     f'你可以在201服务器上的home/cxh/路径下找到colorlog的安装文件\n'
        #     f'你可以选择whl安装文件, 并在终端中执行\n'
        #     f'\tpython -m pip install colorlog-4.6.2-py2.py3-none-any.whl\n'
        #     r'或者直接将colorlog文件夹粘贴到当前环境中Lib\site-packages\文件夹下')
        colorlog = None

    # 输入参数检查及配置============================================================
    if log_name is None:
        # 获取当前栈帧信息
        current_frame = inspect.currentframe()
        # 获取调用者的栈帧信息
        caller_frame = inspect.getouterframes(current_frame, 2)
        # 获取调用者所在的文件名
        caller_filename = caller_frame[1].filename  # 绝对路径
        # 相对工作目录的模块路径
        module_path = os.path.relpath(caller_filename, WORK_DIR)
        # 清理资源
        del current_frame, caller_frame
        # 举例, 'corekit/config/settings.py' -> 'corekit.config.settings.py'
        module_path = module_path.replace(os.path.sep, '.')
        # log_name = os.path.basename(caller_filename)
        log_name = module_path
    else:
        if '/' in log_name or '\\' in log_name:
            # 是一个路径名, 仅需文件名即可
            log_name = os.path.basename(log_name)
    if log_level is None:
        system = sys.platform
        if system.startswith('win'):
            log_level = top_log_level_control.get(log_name, logging.DEBUG)
        else:
            log_level = logging.DEBUG

    default_formatter: str = '%(levelname)s of %(name)s, line %(lineno)d:\t%(message)s'
    if formatter is None:
        formatter: str = default_formatter
    if isinstance(datefmt, int):
        datetime_formats = [
            '%H:%M:%S',  # 比如, 16:15:48
            '%H:%M:%S',  # 比如, 16:15:48,124
            '%Y-%m-%d %H:%M:%S',  # 比如, 2023-10-14 16:15:48
            '%Y-%m-%d %H:%M:%S',  # 比如, 2023-10-14 16:15:48,124
        ]
        time_str = [
            '%(asctime)s ',  # 比如, 16:15:48
            '%(asctime)s,%(msecs)d ',  # 比如, 16:15:48,124
            '%(asctime)s ',  # 比如, 2023-10-14 16:15:48
            '%(asctime)s,%(msecs)d ',  # 比如, 2023-10-14 16:15:48,124
        ]
        formatter = time_str[datefmt] + formatter
        datefmt: str = datetime_formats[datefmt]

    log_colors = {
        'DEBUG': 'white',  # 'cyan',
        'INFO': 'green',
        'WARNING': 'yellow',
        'ERROR': 'red',
        'CRITICAL': 'red',
    }
    # 输入参数检查及配置============================================================

    # 创建logger对象
    logger = logging.getLogger(log_name)
    logger.setLevel(logging.DEBUG)
    logger.propagate = False  # 避免消息被传给 parent logger
    # 创建控制台日志处理器
    console_handler = logging.StreamHandler()
    console_handler.setLevel(log_level)
    # 定义输出格式/颜色控制
    if colorlog is not None:
        sh = colorlog.ColoredFormatter(
            '%(log_color)s' + formatter,
            log_colors=log_colors,
            datefmt=datefmt,
        )
    else:
        sh = logging.Formatter(formatter, datefmt=datefmt)
    console_handler.setFormatter(sh, )

    # 移除默认的handler, 防止重复打印
    for handler in logger.handlers:
        logger.removeHandler(handler)  # 多线程情况下, 会打印多次, 需要多线程打印功能, 请注释这个循环
    for _ in logger.root.handlers:
        logger.root.handlers.pop()

    # 将handler添加到logger对象
    logger.addHandler(console_handler)
    # logger.root.handlers.append(console_handler)

    # logger文件输出设置
    if filename is not None:
        if filename is True:
            filename = f'log/{log_name.split(".")[0]}.log'
        if '.log' not in filename:
            filename = f'{filename}.log'
        if '\\' not in filename and '/' not in filename:  # 非路径名
            filename = f'log/{filename}'
        file_handler = logging.FileHandler(filename, encoding='utf-8')
        file_handler.setLevel(logging.DEBUG)
        file_formatter = logging.Formatter('%(acstime)s %(levelname)s: %(message)s')
        file_handler.setFormatter(file_formatter)
        logger.addHandler(file_handler)

    return logger


class GetDebugLogger:
    """
    生成logger类
    """

    def __init__(
        self,
        log_name: str = None,
        *,
        log_level: int = None,
        formatter: str = None,
        datefmt: int = None,
        filename: str = None,
    ):
        """
        生成日志对象logger, 帮助开发过程中控制台的调试
        :param log_name: str, 日志名, 默认为 f'{__name__}.py'
        :param log_level: 日志级别
        :param formatter: log格式控制
        :param datefmt: 时间格式
        :param filename: 日志文件名
        :return: logger对象
        """
        try:
            import colorlog
        except ImportError:
            print(
                f'没有<colorlog>模块, 无法使用彩色日志功能\n'
                f'你可以在201服务器上的home/cxh/路径下找到colorlog的安装文件\n'
                f'你可以选择whl安装文件, 并在终端中执行\n'
                f'\tpython -m pip install colorlog-4.6.2-py2.py3-none-any.whl\n'
                r'或者直接将colorlog文件夹粘贴到当前环境中Lib\site-packages\文件夹下')
            colorlog = None

            # 输入参数检查及配置============================================================
        if log_name is None:
            log_name = f'{__name__}.py'
        else:
            if '/' in log_name or '\\' in log_name:
                # 是一个路径名, 仅需文件名即可
                log_name = os.path.basename(log_name)
        if log_level is None:
            system = sys.platform
            if system.startswith('win'):
                log_level = top_log_level_control.get(log_name, logging.DEBUG)
            else:
                log_level = logging.WARNING

        default_formatter: str = '%(levelname)s of %(name)s, line %(lineno)d:\t%(message)s'
        if formatter is None:
            formatter: str = default_formatter
        if isinstance(datefmt, int):
            datetime_formats = [
                '%H:%M:%S',  # 比如, 16:15:48
                '%H:%M:%S',  # 比如, 16:15:48,124
                '%Y-%m-%d %H:%M:%S',  # 比如, 2023-10-14 16:15:48,124
                '%Y-%m-%d %H:%M:%S',  # 比如, 2023-10-14 16:15:48,124
                # None,  # 比如, 2023-10-14 16:15:48,124
            ]
            time_str = [
                '%(asctime)s ',  # 比如, 16:15:48
                '%(asctime)s,%(msecs)d ',  # 比如, 16:15:48,124
                '%(asctime)s ',  # 比如, 2023-10-14 16:15:48
                '%(asctime)s,%(msecs)d ',  # 比如, 2023-10-14 16:15:48,124
            ]
            formatter = time_str[datefmt] + formatter
            datefmt: str = datetime_formats[datefmt]

        log_colors = {
            'DEBUG': 'white',  # 'cyan',
            'INFO': 'green',
            'WARNING': 'yellow',
            'ERROR': 'red',
            'CRITICAL': 'red',
        }
        # 输入参数检查及配置============================================================

        # 创建logger对象
        logger = logging.getLogger(log_name)
        logger.setLevel(logging.DEBUG)
        # 创建控制台日志处理器
        console_handler = logging.StreamHandler()
        console_handler.setLevel(log_level)
        # 定义输出格式/颜色控制
        if colorlog is not None:
            sh = colorlog.ColoredFormatter(
                '%(log_color)s' + formatter,
                log_colors=log_colors,
                datefmt=datefmt,
            )
        else:
            sh = logging.Formatter(formatter, datefmt=datefmt)
        console_handler.setFormatter(sh, )

        # 移除默认的handler, 防止重复打印
        for handler in logger.handlers:
            logger.removeHandler(handler)
        for _ in logger.root.handlers:
            logger.root.handlers.pop()

        # 将handler添加到logger对象
        logger.addHandler(console_handler)
        # logger.root.handlers.append(console_handler)

        # logger文件输出设置
        if filename is not None:
            if filename is True:
                filename = f'logs/{log_name.split(".")[0]}.log'
            if '.log' not in filename:
                filename = f'{filename}.log'
            if '\\' not in filename and '/' not in filename:  # 非路径名
                filename = f'logs/{filename}'
            file_handler = logging.FileHandler(filename, encoding='utf-8')
            file_handler.setLevel(logging.DEBUG)
            file_formatter = logging.Formatter('%(acstime)s %(levelname)s: %(message)s')
            file_handler.setFormatter(file_formatter)
            logger.addHandler(file_handler)

        self.logger = logger

    def debug(self, *args):
        """
        debug
        :param args:
        :return:
        """
        msg = ''
        for str_i in args:
            msg += str(str_i)

        self.logger.debug(msg)

    def info(self, *args):
        """
        info
        :param args:
        :return:
        """
        msg = ''
        for str_i in args:
            msg += str(str_i)

        self.logger.info(msg)

    def warning(self, *args):
        """
        info
        :param args:
        :return:
        """
        msg = ''
        for str_i in args:
            msg += str(str_i)

        self.logger.warning(msg)

    def error(self, *args):
        """
        info
        :param args:
        :return:
        """
        msg = ''
        for str_i in args:
            msg += str(str_i)

        self.logger.error(msg)

    def critical(self, *args):
        """
        info
        :param args:
        :return:
        """
        msg = ''
        for str_i in args:
            msg += str(str_i)

        self.logger.critical(msg)


if __name__ == '__main__':
    import numpy as np

    np.set_printoptions(suppress=True)

    _logger = get_debug_logger('test')
    # alog = logging.getLogger('a')
    # logging.warning(1, 2, 3)
    _logger.info(1, 2, 3)
    # f = logging.Formatter()
    # log模块测试demo
    # test_log = GetDebugLogger()
    # for _ in range(30):
    #     i = np.random.choice(12)
    #     if i % 2 == 0:
    #         test_log.debug('偶数')
    #     elif i <= 5:
    #         test_log.info(f'小数')
    #     elif i == 7:
    #         test_log.warning(f'7')
    #     elif i == 9:
    #         test_log.error(f'9')
    #     else:
    #         test_log.critical(f'11')

    # log = GetDebugLogger()
    pass
