import logging
from tqdm import tqdm
import time

class TqdmLoggingHandler(logging.Handler):
    """确保日志输出与tqdm进度条兼容"""
    def __init__(self, level=logging.NOTSET):
        super().__init__(level)

    def emit(self, record):
        try:
            msg = self.format(record)
            tqdm.write(msg)
            self.flush()
        except Exception:
            self.handleError(record)

class ColorFormatter:
    """颜色格式工具类"""
    # ANSI颜色代码
    COLORS = {
        'black': '\033[30m',
        'red': '\033[31m',
        'green': '\033[32m',
        'yellow': '\033[33m',
        'blue': '\033[34m',
        'magenta': '\033[35m',
        'cyan': '\033[36m',
        'white': '\033[37m',
        'reset': '\033[0m',
        'bright_black': '\033[90m',
        'bright_red': '\033[91m',
        'bright_green': '\033[92m',
        'bright_yellow': '\033[93m',
        'bright_blue': '\033[94m',
        'bright_magenta': '\033[95m',
        'bright_cyan': '\033[96m',
        'bright_white': '\033[97m',
    }
    
    @classmethod
    def colorize(cls, text, color_name):
        """为文本着色，如果颜色名为None则返回原文本"""
        if color_name is None:
            return text
        
        color_code = cls.COLORS.get(color_name.lower(), cls.COLORS['reset'])
        return f"{color_code}{text}{cls.COLORS['reset']}"

class ConsoleFormatter(logging.Formatter):
    """控制台日志格式化器，支持部分文字着色"""
    def format(self, record):
        """重写format方法，支持部分文字着色"""
        # 保存原始消息，用于文件日志
        original_msg = record.msg
        
        # 如果有颜色部分，构建带颜色的消息
        if hasattr(record, 'color_parts'):
            colored_parts = []
            for part in record.color_parts:
                if isinstance(part, tuple):
                    text, color = part
                    colored_parts.append(ColorFormatter.colorize(text, color))
                else:
                    colored_parts.append(str(part))
            
            # 临时设置消息为带颜色的消息（只影响控制台日志）
            record.msg = ''.join(colored_parts)
        
        # 调用父类格式化方法
        result = super().format(record)
        
        # 恢复原始消息（确保文件日志使用原始消息）
        record.msg = original_msg
        
        return result

class FileFormatter(logging.Formatter):
    """文件日志格式化器，移除所有颜色标记"""
    def format(self, record):
        # 如果有颜色部分，构建纯文本消息
        if hasattr(record, 'color_parts'):
            # 保存原始消息
            original_msg = record.msg
            
            # 构建纯文本消息
            plain_parts = []
            for part in record.color_parts:
                if isinstance(part, tuple):
                    plain_parts.append(part[0])
                else:
                    plain_parts.append(str(part))
            
            # 临时设置纯文本消息
            record.msg = ''.join(plain_parts)
            
            # 调用父类格式化方法
            result = super().format(record)
            
            # 恢复原始消息
            record.msg = original_msg
            return result
        
        # 没有颜色部分，直接调用父类方法
        return super().format(record)

class ProgressLogger:
    def __init__(self, log_file='app.log'):
        self.logger = logging.getLogger(__name__)
        self.logger.setLevel(logging.DEBUG)
        self.log_file = log_file
        self._setup_logger()
        
    def _setup_logger(self):
        # 移除所有现有处理器（避免重复）
        if self.logger.hasHandlers():
            self.logger.handlers.clear()
        
        # 创建带颜色的控制台输出
        console_format = '%(asctime)s [%(levelname)s] %(message)s'
        
        console_handler = TqdmLoggingHandler()
        console_handler.setFormatter(ConsoleFormatter(console_format, datefmt='%H:%M:%S'))
        
        # 创建文件输出（无颜色）
        file_format = '%(asctime)s [%(levelname)s] %(message)s'
        
        file_handler = logging.FileHandler(self.log_file)
        file_handler.setFormatter(FileFormatter(file_format, datefmt='%Y-%m-%d %H:%M:%S'))
        
        # 添加处理器
        self.logger.addHandler(console_handler)
        self.logger.addHandler(file_handler)
    
    def progress_bar(self, iterable, desc=None, **kwargs):
        """创建带日志集成的进度条"""
        return tqdm(
            iterable,
            desc=desc,
            # bar_format='{l_bar}{bar}| {n_fmt}/{total_fmt} ',
            **kwargs
        )
    
    def _log(self, level, *parts):
        """内部日志方法，支持部分着色"""
        # 将混合格式转换为统一格式
        formatted_parts = []
        plain_message = []
        
        for part in parts:
            if isinstance(part, tuple) and len(part) == 2:
                formatted_parts.append(part)
                plain_message.append(part[0])
            else:
                text = str(part)
                formatted_parts.append((text, None))
                plain_message.append(text)
        
        # 设置记录的原始消息（纯文本）
        plain_msg = ''.join(plain_message)
        self.logger.log(level, plain_msg, extra={'color_parts': formatted_parts})
    
    # 用户友好的日志方法，支持部分着色
    def debug(self, *parts):
        self._log(logging.DEBUG, *parts)
    
    def info(self, *parts):
        self._log(logging.INFO, *parts)
    
    def warning(self, *parts):
        self._log(logging.WARNING, *parts)
    
    def error(self, *parts):
        self._log(logging.ERROR, *parts)
    
    def critical(self, *parts):
        self._log(logging.CRITICAL, *parts)
    
    def success(self, *parts):
        """自定义成功消息（绿色）"""
        self.info(('SUCCESS: ', 'green'), *parts)

# 使用示例
if __name__ == "__main__":
    plog = ProgressLogger('app.log')
    
    # 示例1: 混合格式的日志消息
    plog.info(
        "这是一个", 
        ("混合颜色", "red"), 
        "的日志消息，可以",
        ("在同一行", "blue"),
        ("使用多种颜色", "yellow")
    )
    
    # 示例2: 自定义成功消息
    plog.success("数据处理完成")
    
    # 示例3: 复杂着色
    plog.warning(
        ("警告: ", "bright_red"),
        "文件",
        ("config.ini", "cyan"),
        ("未找到! ", "bright_red"),
        "使用",
        ("默认配置", "green")
    )
    
    # 示例4: 带进度条和日志的组合
    items = range(100)
    with plog.progress_bar(items, desc="处理数据") as pbar:
        for item in pbar:
            time.sleep(0.05)  # 模拟工作
            
            if item == 25:
                # 进度条中显示带颜色的消息
                plog.info(
                    "到达", 
                    ("25", "bright_yellow"), 
                    "个物品，", 
                    ("状态正常", "green")
                )
                
            elif item == 50:
                plog.warning(
                    "警告: 到达", 
                    ("50", "bright_red"), 
                    "个物品，资源使用",
                    ("较高", "bright_red")
                )
                pbar.set_postfix(status="警告状态")
                
            elif item == 75:
                plog.error(
                    ("错误: ", "bright_red"),
                    "物品",
                    ("#75", "bright_white"),
                    ("处理失败! ", "bright_red")
                )
                pbar.set_postfix(status="错误状态")
    
    # 示例5: 只有文字的消息
    plog.info("这条消息没有任何颜色标记")
    
    # 查看文件日志
    print("\n查看文件日志内容:")
    try:
        with open('app.log', 'r') as f:
            print(f.read())
    except FileNotFoundError:
        print("日志文件不存在，可能是第一次运行")
