import logging
import colorlog
import asyncio
from collections import deque
from asyncio import Queue
from typing import List

CACHED_SIZE = 200
log_color_config = {
    'DEBUG': 'green', 'INFO': 'bold_cyan',
    'WARNING': 'bold_yellow', 'ERROR': 'red',
    'CRITICAL': 'bold_red', 'RESET': 'reset',
    'asctime': 'green'
}

class LogBroker:
    def __init__(self):
        self.log_cache = deque(maxlen=CACHED_SIZE)
        self.subscribers: List[Queue] = []
    
    def register(self) -> Queue:
        '''给每个订阅者返回一个带有日志缓存的队列'''
        q = Queue(maxsize=CACHED_SIZE + 10)
        for log in self.log_cache:
            q.put_nowait(log)
        self.subscribers.append(q)
        return q
    
    def unregister(self, q: Queue):
        '''取消订阅'''
        self.subscribers.remove(q)
        
    def publish(self, log_entry: str):
        '''发布消息'''
        self.log_cache.append(log_entry)
        for q in self.subscribers:
            try:
                q.put_nowait(log_entry)
            except asyncio.QueueFull:
                pass

class LogQueueHandler(logging.Handler):
    def __init__(self, log_broker: LogBroker):
        super().__init__()
        self.log_broker = log_broker

    def emit(self, record):
        log_entry = self.format(record)
        self.log_broker.publish(log_entry)

class LogManager:

    @classmethod
    def GetLogger(cls, log_name: str = 'default'):
        logger = logging.getLogger(log_name)
        if logger.hasHandlers():
            return logger
        console_handler = logging.StreamHandler()
        console_handler.setLevel(logging.DEBUG)
        console_formatter = colorlog.ColoredFormatter(
            fmt='%(log_color)s [%(asctime)s] [%(levelname)-5s] [%(filename)s:%(lineno)d]: %(message)s %(reset)s',
            datefmt='%H:%M:%S',
            log_colors=log_color_config
        )
        console_handler.setFormatter(console_formatter)
        logger.setLevel(logging.DEBUG)
        logger.addHandler(console_handler)
        
        return logger
    
    @classmethod
    def set_queue_handler(cls, logger: logging.Logger, log_broker: LogBroker):
        handler = LogQueueHandler(log_broker)
        handler.setLevel(logging.DEBUG)
        if logger.handlers:
            handler.setFormatter(logger.handlers[0].formatter)
        else:
            handler.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
        logger.addHandler(handler)