#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# @Author:      thepoy
# @Email:       thepoy@163.com
# @File Name:   logger.py
# @Created At:  2021-05-21 13:53:40
# @Modified At: 2023-02-21 10:47:25
# @Modified By: thepoy

import os
import sys
import queue

from typing import NoReturn, Optional
from logging import Logger
from logging.handlers import QueueListener
from colorful_logger.types import StrPath

from colorful_logger.handlers import (
    ColorfulQueueHandler,
    ColorfulQueueListener,
    console_handler,
    file_handler,
)
from colorful_logger.consts import DEBUG, WARNING, FATAL, TIME_FORMAT_WITHOUT_DATE


default_level = WARNING


def is_debug() -> bool:
    v = os.getenv("DEBUG")

    if not v or v == "0" or v.lower() == "false":
        return False

    if v == "1" or v.lower() == "true":
        return True

    return False


if is_debug():
    default_level = DEBUG


class ColorfulLogger(Logger):
    def addListener(self, listener: QueueListener):
        self.listener = listener

    def fatal(self, msg, *args, **kwargs) -> NoReturn:
        if self.isEnabledFor(FATAL):
            # NOTE: 因为这里调用了 fatal， stacklevel 需要设置为 2 才是真正的调用位置
            self._log(FATAL, msg, args, **kwargs, stacklevel=2)
        sys.exit(1)

    def __enter__(self):
        self.listener.start()
        return self

    def __exit__(self, *args):
        self.listener.stop()

    def child(self, name: str) -> "ColorfulLogger":
        lc = ColorfulLogger(name)
        lc.level = self.level
        lc.handlers = self.handlers
        lc.listener = self.listener
        # lc.propagate = False
        return lc


def get_logger(
    name: Optional[str] = None,
    level: int = default_level,
    datefmt: str = TIME_FORMAT_WITHOUT_DATE,
    show: bool = True,
    file_path: Optional[StrPath] = None,
    file_colorful: bool = False,
    add_file_path: bool = True,
    disable_line_number_filter: bool = False,
) -> ColorfulLogger:
    """Return a colorful logger with the specified name, creating it if necessary.

    If no name is specified, return the root logger.

    Args:
        name (Optional[str], optional): logger name.
        level (str, None): The logging level of this logger, default level is WARNING.
        show (bool, True): Whether the log is displayed in the terminal, default is True.
        file_path (str, None): When 'file_path' is not None, the log will be saved to 'file_path'.
        file_colorful (bool, False): Whether the log file is in color, the default is False.
        add_file_path (bool, True): Whether to add the path of the calling file, the default is False.
        disable_line_number_filter (bool, False): Whether to add the number of calling line in all levels of logs, the default is False.

    Returns:
        ColorfulLogger: logger
    """

    if not file_path and not show:
        raise NotImplementedError(
            "the log must be displayed in the terminal or saved to a file"
        )

    name = name if name else "root"
    logger = ColorfulLogger(name)

    q = queue.Queue(-1)  # no limit on size
    queue_handler = ColorfulQueueHandler(q)
    logger.addHandler(queue_handler)

    logger.setLevel(level)

    handlers = []
    if show:
        handlers.append(
            console_handler(
                datefmt,
                add_file_path=add_file_path,
                disable_line_number_filter=disable_line_number_filter,
            )
        )
    if file_path:
        handlers.append(
            file_handler(
                file_path,
                file_colorful,
                datefmt,
                add_file_path=add_file_path,
                disable_line_number_filter=disable_line_number_filter,
            )
        )

    listener = ColorfulQueueListener(
        q,
        *handlers,
    )

    logger.addListener(listener)

    return logger


logger = get_logger()


def child_logger(name: str, logger: ColorfulLogger = logger) -> ColorfulLogger:
    """Generate a child logger through the incoming logger

    Args:
        name (str): child logger name
        logger (Logger, optional): parent logger, default is the logger generated by the get_logger function

    Returns:
        ColorfulLogger: child logger
    """

    return logger.child(name)
