"""任务级日志缓冲区，收集单个任务的所有日志，任务完成后一次性输出。

解决多任务并行执行时日志行交叉混乱的问题：每个任务维护独立的缓冲区，
任务完成后将完整日志按时间顺序一次性输出到父 logger，添加 [task_code] 前缀。
"""

from __future__ import annotations

import logging
import threading
from dataclasses import dataclass, field
from datetime import datetime


@dataclass
class LogEntry:
    """日志条目。"""

    timestamp: datetime
    level: int
    task_code: str
    message: str


class TaskLogBuffer:
    """任务级日志缓冲区，收集单个任务的所有日志，任务完成后一次性输出。

    所有写入操作线程安全（内部使用 threading.Lock）。
    """

    def __init__(self, task_code: str, parent_logger: logging.Logger) -> None:
        """初始化日志缓冲区。

        Args:
            task_code: 任务代码，用于日志前缀标识。
            parent_logger: 父 logger，flush() 时日志输出的目标。
        """
        self.task_code = task_code
        self._parent = parent_logger
        self._buffer: list[LogEntry] = []
        self._lock = threading.Lock()

    def log(self, level: int, message: str, *args: object) -> None:
        """线程安全地缓冲一条日志。

        Args:
            level: 日志级别（如 logging.INFO）。
            message: 日志消息，支持 % 格式化。
            *args: 格式化参数。
        """
        formatted = message % args if args else message
        entry = LogEntry(
            timestamp=datetime.now(),
            level=level,
            task_code=self.task_code,
            message=formatted,
        )
        with self._lock:
            self._buffer.append(entry)

    # ---- 便捷方法 ----

    def debug(self, message: str, *args: object) -> None:
        self.log(logging.DEBUG, message, *args)

    def info(self, message: str, *args: object) -> None:
        self.log(logging.INFO, message, *args)

    def warning(self, message: str, *args: object) -> None:
        self.log(logging.WARNING, message, *args)

    def error(self, message: str, *args: object) -> None:
        self.log(logging.ERROR, message, *args)

    # ---- 输出 ----

    def flush(self) -> list[LogEntry]:
        """将缓冲区内容按时间顺序一次性输出到父 logger，并清空缓冲区。

        输出时每条日志添加 [task_code] 前缀，保证日志归属可识别。

        Returns:
            按时间戳升序排列的日志条目列表（副本）。
        """
        with self._lock:
            entries = sorted(self._buffer, key=lambda e: e.timestamp)
            for entry in entries:
                self._parent.log(
                    entry.level,
                    "[%s] %s",
                    entry.task_code,
                    entry.message,
                )
            self._buffer.clear()
            return list(entries)

    @property
    def entries(self) -> list[LogEntry]:
        """返回当前缓冲区条目的副本（用于测试/检查）。"""
        with self._lock:
            return list(self._buffer)
