"""
日志管理工具模块

提供统一的日志管理功能，支持：
- 控制台日志输出
- 文件日志输出（按天轮转）
- 多级别日志控制
- 线程安全的单例模式
- 配置文件加载

Example:
    >>> logger = Xlog.get_logger("config.ini")
    >>> logger.info("Application started")
    >>> logger.error("An error occurred", exc_info=True)
"""
import os
import logging
import threading
from typing import Optional, Dict, Any, Union

from xsdk.config_reader import ConfigReader
from logging.handlers import TimedRotatingFileHandler

# 全局线程锁，用于单例模式
_lock = threading.Lock()

# 默认日志格式
DEFAULT_LOG_FORMAT = (
    "[%(asctime)s.%(msecs)03d %(levelname)s] "
    "[%(thread)d] (%(filename)s:%(lineno)d) %(message)s"
)
DEFAULT_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"


class XlogConfig:
    """
    日志配置类

    封装日志相关的配置参数。

    Attributes:
        log_level: 全局日志级别
        console_log_flag: 是否输出到控制台
        file_log_flag: 是否输出到文件
        file_log_path: 日志文件目录
        file_log_name: 日志文件名

    Example:
        >>> config = XlogConfig(
        ...     log_level=logging.DEBUG,
        ...     console_log_flag=True,
        ...     file_log_flag=True,
        ...     file_log_path="./logs"
        ... )
    """

    def __init__(
        self,
        log_level: int = logging.DEBUG,
        console_log_flag: bool = True,
        file_log_flag: bool = False,
        file_log_path: str = "../log",
        file_log_name: str = "xlog.log"
    ):
        """
        初始化日志配置

        Args:
            log_level: 全局日志级别
            console_log_flag: 是否输出到控制台
            file_log_flag: 是否输出到文件
            file_log_path: 日志文件目录
            file_log_name: 日志文件名
        """
        self.log_level: int = log_level
        self.console_log_flag: bool = console_log_flag
        self.file_log_flag: bool = file_log_flag
        self.file_log_path: str = file_log_path
        self.file_log_name: str = file_log_name

    def __str__(self) -> str:
        """
        返回配置的字符串表示

        Returns:
            配置字典的字符串形式
        """
        return str(self.__dict__)

    @staticmethod
    def get_config(conf_file: str, conf_section: str = "xlog") -> "XlogConfig":
        """
        从配置文件加载日志配置

        Args:
            conf_file: 配置文件路径
            conf_section: 配置Section名称

        Returns:
            XlogConfig实例
        """
        config_reader = ConfigReader.get_instance(conf_file)
        log_level = config_reader.get(conf_section, "log_level")
        console_log_flag = config_reader.get(conf_section, "console_log_flag")
        file_log_flag = config_reader.get(conf_section, "file_log_flag")
        file_log_path = config_reader.get(conf_section, "file_log_path")
        file_log_name = config_reader.get(conf_section, "file_log_name")

        # 转换日志级别
        log_level = XlogConfig.get_log_level(log_level)

        # 转换布尔值
        console_log_flag = str(console_log_flag).lower() in ["y", "true"]
        file_log_flag = str(file_log_flag).lower() in ["y", "true"]

        # 至少开启一种日志模式
        if not console_log_flag and not file_log_flag:
            console_log_flag = True

        # 创建日志目录
        if file_log_flag and not os.path.exists(file_log_path):
            os.makedirs(file_log_path)

        return XlogConfig(
            log_level=log_level,
            console_log_flag=console_log_flag,
            file_log_flag=file_log_flag,
            file_log_path=file_log_path,
            file_log_name=file_log_name
        )

    @staticmethod
    def parse_dict(data_dict: Optional[Dict[str, Any]]) -> "XlogConfig":
        """
        从字典解析日志配置

        Args:
            data_dict: 配置字典

        Returns:
            XlogConfig实例
        """
        log_conf = XlogConfig()
        if data_dict is None or len(data_dict) == 0:
            return log_conf

        # 更新配置属性
        for key, value in data_dict.items():
            if key in log_conf.__dict__:
                log_conf.__dict__[key] = value

        # 转换布尔值
        log_conf.console_log_flag = str(log_conf.console_log_flag).lower() in ["y", "true"]
        log_conf.file_log_flag = str(log_conf.file_log_flag).lower() in ["y", "true"]

        # 至少开启一种日志模式
        if not log_conf.console_log_flag and not log_conf.file_log_flag:
            log_conf.console_log_flag = True

        # 创建日志目录
        if log_conf.file_log_flag and not os.path.exists(log_conf.file_log_path):
            os.makedirs(log_conf.file_log_path)

        return log_conf

    @staticmethod
    def get_log_level(log_level: Union[str, int]) -> int:
        """
        获取日志级别的数值

        Args:
            log_level: 日志级别（字符串或整数）

        Returns:
            日志级别数值
        """
        if isinstance(log_level, int):
            return log_level

        level = logging.getLevelName(str(log_level).upper())
        if isinstance(level, int):
            return level
        return logging.INFO


class Xlog:
    """
    日志管理类

    提供线程安全的日志记录功能，支持控制台和文件输出。

    Attributes:
        logger: 类级别的单例logger实例
        log_conf: 日志配置

    Example:
        >>> logger = Xlog.get_logger("config.ini")
        >>> logger.info("Processing data...")
        >>> logger.error("Error occurred", exc_info=True)
    """

    logger: Optional["Xlog"] = None

    def __init__(self, log_conf: Union[XlogConfig, Dict[str, Any]]):
        """
        初始化日志管理器

        Args:
            log_conf: 日志配置对象或字典
        """
        if isinstance(log_conf, dict):
            log_conf = XlogConfig.parse_dict(log_conf)
        self.log_conf: XlogConfig = log_conf
        self._logger: Optional[logging.Logger] = None
        self._init()

    def _init(self) -> None:
        """
        初始化日志处理器

        配置控制台和文件日志处理器。
        """
        self._logger = logging.getLogger("Xlog")
        self._logger.handlers.clear()  # 添加这行
        self._logger.setLevel(self.log_conf.log_level)

        formatter = logging.Formatter(
            fmt=DEFAULT_LOG_FORMAT,
            datefmt=DEFAULT_DATE_FORMAT
        )

        # 控制台日志处理器
        if self.log_conf.console_log_flag:
            handler_console = logging.StreamHandler()
            handler_console.setLevel(self.log_conf.log_level)
            handler_console.setFormatter(formatter)
            self._logger.addHandler(handler_console)

        # 文件日志处理器（按天轮转，保留45天）
        if self.log_conf.file_log_flag:
            log_file = f"{self.log_conf.file_log_path}/{self.log_conf.file_log_name}"
            handler_file = TimedRotatingFileHandler(
                log_file,
                when="D",
                interval=1,
                backupCount=45
            )
            handler_file.setLevel(self.log_conf.log_level)
            handler_file.setFormatter(formatter)
            self._logger.addHandler(handler_file)

    @staticmethod
    def get_logger(conf_file: str, conf_section: str = "xlog") -> "Xlog":
        """
        获取日志管理器单例

        线程安全的单例模式，确保全局只有一个日志实例。

        Args:
            conf_file: 配置文件路径
            conf_section: 配置Section名称

        Returns:
            Xlog单例实例
        """
        if Xlog.logger is None:
            with _lock:
                if Xlog.logger is None:
                    log_conf = XlogConfig.get_config(conf_file, conf_section)
                    Xlog.logger = Xlog(log_conf)
        return Xlog.logger

    @staticmethod
    def get_default_logger(log_level: str = "INFO") -> logging.Logger:
        """
        获取默认的Python logger

        Args:
            log_level: 日志级别

        Returns:
            标准logging.Logger实例
        """
        return logging.getLogger("DefaultLogger")

    def set_level(self, log_level: str = "INFO") -> None:
        """
        动态设置日志级别

        Args:
            log_level: 日志级别字符串
        """
        level = XlogConfig.get_log_level(log_level)
        self._logger.setLevel(level)

    @staticmethod
    def _get_stack_level(kwargs: Dict[str, Any]) -> int:
        """
        从kwargs中提取stacklevel参数

        Args:
            kwargs: 关键字参数字典

        Returns:
            stacklevel值
        """
        sl1 = kwargs.pop("stacklevel", None)
        sl2 = kwargs.pop("stack_level", None)
        stack_level = sl1 if sl1 is not None else sl2

        try:
            stack_level = int(str(stack_level))
        except (ValueError, TypeError):
            stack_level = 2

        return max(1, stack_level)

    def debug(self, msg: str, *args: Any, **kwargs: Any) -> None:
        """
        记录DEBUG级别日志

        Args:
            msg: 日志消息
            *args: 格式化参数
            **kwargs: 关键字参数
        """
        stack_level = Xlog._get_stack_level(kwargs)
        self._logger.debug(msg, *args, stacklevel=stack_level, **kwargs)

    def info(self, msg: str, *args: Any, **kwargs: Any) -> None:
        """
        记录INFO级别日志

        Args:
            msg: 日志消息
            *args: 格式化参数
            **kwargs: 关键字参数
        """
        stack_level = Xlog._get_stack_level(kwargs)
        self._logger.info(msg, *args, stacklevel=stack_level, **kwargs)

    def warn(self, msg: str, *args: Any, **kwargs: Any) -> None:
        """
        记录WARNING级别日志（warn别名）

        Args:
            msg: 日志消息
            *args: 格式化参数
            **kwargs: 关键字参数
        """
        stack_level = Xlog._get_stack_level(kwargs)
        self._logger.warning(msg, *args, stacklevel=stack_level, **kwargs)

    def warning(self, msg: str, *args: Any, **kwargs: Any) -> None:
        """
        记录WARNING级别日志

        Args:
            msg: 日志消息
            *args: 格式化参数
            **kwargs: 关键字参数
        """
        stack_level = Xlog._get_stack_level(kwargs)
        self._logger.warning(msg, *args, stacklevel=stack_level, **kwargs)

    def error(self, msg: str, *args: Any, **kwargs: Any) -> None:
        """
        记录ERROR级别日志

        Args:
            msg: 日志消息
            *args: 格式化参数
            **kwargs: 关键字参数
        """
        stack_level = Xlog._get_stack_level(kwargs)
        self._logger.error(msg, *args, stacklevel=stack_level, **kwargs)

    def fatal(self, msg: str, *args: Any, **kwargs: Any) -> None:
        """
        记录FATAL级别日志

        Args:
            msg: 日志消息
            *args: 格式化参数
            **kwargs: 关键字参数
        """
        stack_level = Xlog._get_stack_level(kwargs)
        self._logger.fatal(msg, *args, stacklevel=stack_level, **kwargs)

    def exception(
        self,
        msg: str,
        *args: Any,
        exc_info: bool = True,
        **kwargs: Any
    ) -> None:
        """
        记录异常日志

        Args:
            msg: 日志消息
            *args: 格式化参数
            exc_info: 是否包含异常信息
            **kwargs: 关键字参数
        """
        stack_level = Xlog._get_stack_level(kwargs)
        self._logger.exception(msg, *args, exc_info=exc_info, stacklevel=stack_level, **kwargs)


if __name__ == "__main__":
    pass
