# -*- coding: utf-8 -*-
"""
统一日志配置模块
提供系统级别的日志配置和管理
"""

import os
import sys
import logging
from logging.handlers import RotatingFileHandler, TimedRotatingFileHandler
from datetime import datetime
from pathlib import Path


class LoggerConfig:
    """日志配置管理类"""
    
    def __init__(self, logs_dir: str = None):
        """初始化日志配置
        
        Args:
            logs_dir: 日志目录路径，默认为项目根目录下的logs文件夹
        """
        # 确定日志目录
        if logs_dir:
            self.logs_dir = Path(logs_dir)
        else:
            # 获取项目根目录（logger_config.py 在 utils 目录下，需要上升两层到达项目根目录）
            project_root = Path(__file__).parent.parent
            self.logs_dir = project_root / "logs"
        
        # 创建日志目录
        self.logs_dir.mkdir(exist_ok=True)
        
        # 日志格式
        self.log_format = '%(asctime)s - %(name)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s'
        self.date_format = '%Y-%m-%d %H:%M:%S'
        
        # 从环境变量获取日志级别，默认为INFO
        self.log_level = self._get_log_level_from_env()
        
        # 是否已初始化
        self._initialized = False
    
    def _get_log_level_from_env(self) -> int:
        """从环境变量获取日志级别
        
        Returns:
            int: 日志级别
        """
        log_level_str = os.getenv('LOG_LEVEL', 'INFO').upper()
        
        # 日志级别映射
        level_mapping = {
            'DEBUG': logging.DEBUG,
            'INFO': logging.INFO,
            'WARNING': logging.WARNING,
            'WARN': logging.WARNING,  # 兼容性别名
            'ERROR': logging.ERROR,
            'CRITICAL': logging.CRITICAL,
            'FATAL': logging.CRITICAL  # 兼容性别名
        }
        
        return level_mapping.get(log_level_str, logging.INFO)
    
    def setup_logging(self, 
                     app_name: str = "lzwcai_mcp_sqlexecutor",
                     log_level: int = logging.INFO,
                     max_file_size: int = 10 * 1024 * 1024,  # 10MB
                     backup_count: int = 5,
                     console_output: bool = True) -> logging.Logger:
        """设置系统日志配置
        
        Args:
            app_name: 应用名称，用于日志文件命名
            log_level: 日志级别
            max_file_size: 单个日志文件最大大小（字节）
            backup_count: 保留的备份文件数量
            console_output: 是否输出到控制台
            
        Returns:
            logging.Logger: 配置好的根日志器
        """
        if self._initialized:
            return logging.getLogger()
        
        # 设置根日志器
        root_logger = logging.getLogger()
        root_logger.setLevel(log_level)
        
        # 清除现有的处理器
        for handler in root_logger.handlers[:]:
            root_logger.removeHandler(handler)
        
        # 创建格式化器
        formatter = logging.Formatter(self.log_format, self.date_format)
        
        # 1. 主日志文件 - 按大小滚动
        main_log_file = self.logs_dir / f"{app_name}.log"
        file_handler = RotatingFileHandler(
            main_log_file,
            maxBytes=max_file_size,
            backupCount=backup_count,
            encoding='utf-8'
        )
        file_handler.setLevel(log_level)
        file_handler.setFormatter(formatter)
        root_logger.addHandler(file_handler)
        
        # 2. 错误日志文件 - 只记录ERROR及以上级别
        error_log_file = self.logs_dir / f"{app_name}_error.log"
        error_handler = RotatingFileHandler(
            error_log_file,
            maxBytes=max_file_size,
            backupCount=backup_count,
            encoding='utf-8'
        )
        error_handler.setLevel(logging.ERROR)
        error_handler.setFormatter(formatter)
        root_logger.addHandler(error_handler)
        
        # 3. 按日期滚动的日志文件
        daily_log_file = self.logs_dir / f"{app_name}_daily.log"
        daily_handler = TimedRotatingFileHandler(
            daily_log_file,
            when='midnight',
            interval=1,
            backupCount=30,  # 保留30天
            encoding='utf-8'
        )
        daily_handler.setLevel(log_level)
        daily_handler.setFormatter(formatter)
        daily_handler.suffix = "%Y-%m-%d"
        root_logger.addHandler(daily_handler)
        
        # 4. 控制台输出
        # 重要：MCP协议使用stdio时，必须将日志输出到stderr，stdout仅用于JSON-RPC通信
        if console_output:
            console_handler = logging.StreamHandler(sys.stderr)
            console_handler.setLevel(log_level)
            console_formatter = logging.Formatter(
                '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
                self.date_format
            )
            console_handler.setFormatter(console_formatter)
            root_logger.addHandler(console_handler)
        
        self._initialized = True
        
        # 记录初始化信息
        root_logger.info(f"日志系统初始化完成 - 日志目录: {self.logs_dir}")
        root_logger.info(f"日志配置 - 级别: {logging.getLevelName(log_level)}, 文件大小限制: {max_file_size//1024//1024}MB, 备份数量: {backup_count}")
        
        return root_logger
    
    def get_module_logger(self, module_name: str) -> logging.Logger:
        """获取模块专用日志器
        
        Args:
            module_name: 模块名称
            
        Returns:
            logging.Logger: 模块日志器
        """
        return logging.getLogger(module_name)
    
    def create_component_logger(self, 
                               component_name: str,
                               log_file: str = None,
                               log_level: int = None) -> logging.Logger:
        """为特定组件创建独立的日志器
        
        Args:
            component_name: 组件名称
            log_file: 独立日志文件名（可选）
            log_level: 日志级别（可选）
            
        Returns:
            logging.Logger: 组件日志器
        """
        logger = logging.getLogger(component_name)
        
        if log_file:
            # 为组件创建独立的日志文件
            component_log_file = self.logs_dir / log_file
            handler = RotatingFileHandler(
                component_log_file,
                maxBytes=5 * 1024 * 1024,  # 5MB
                backupCount=3,
                encoding='utf-8'
            )
            
            formatter = logging.Formatter(self.log_format, self.date_format)
            handler.setFormatter(formatter)
            
            if log_level:
                handler.setLevel(log_level)
            
            logger.addHandler(handler)
            logger.info(f"组件日志器创建完成: {component_name} -> {component_log_file}")
        
        return logger
    
    def setup_mqtt_logging(self) -> logging.Logger:
        """设置MQTT专用日志
        
        Returns:
            logging.Logger: MQTT日志器
        """
        return self.create_component_logger(
            "mqtt_communication",
            "mqtt_communication.log",
            logging.DEBUG
        )
    
    def setup_mcp_logging(self) -> logging.Logger:
        """设置MCP专用日志
        
        Returns:
            logging.Logger: MCP日志器
        """
        return self.create_component_logger(
            "mcp_services",
            "mcp_services.log",
            logging.DEBUG
        )
    
    def setup_api_logging(self) -> logging.Logger:
        """设置API专用日志
        
        Returns:
            logging.Logger: API日志器
        """
        return self.create_component_logger(
            "api_requests",
            "api_requests.log",
            logging.INFO
        )
    
    def get_logs_info(self) -> dict:
        """获取日志系统信息
        
        Returns:
            dict: 日志系统信息
        """
        log_files = []
        if self.logs_dir.exists():
            for log_file in self.logs_dir.glob("*.log*"):
                stat = log_file.stat()
                log_files.append({
                    "name": log_file.name,
                    "size": stat.st_size,
                    "modified": datetime.fromtimestamp(stat.st_mtime).isoformat()
                })
        
        return {
            "logs_directory": str(self.logs_dir),
            "initialized": self._initialized,
            "log_files": log_files,
            "total_files": len(log_files)
        }
    
    def cleanup_old_logs(self, days: int = 30):
        """清理旧日志文件
        
        Args:
            days: 保留天数
        """
        if not self.logs_dir.exists():
            return
        
        from datetime import timedelta
        cutoff_time = datetime.now() - timedelta(days=days)
        
        cleaned_files = []
        for log_file in self.logs_dir.glob("*.log*"):
            if log_file.stat().st_mtime < cutoff_time.timestamp():
                try:
                    log_file.unlink()
                    cleaned_files.append(log_file.name)
                except Exception as e:
                    logging.error(f"清理日志文件失败: {log_file.name}, 错误: {e}")
        
        if cleaned_files:
            logging.info(f"清理了 {len(cleaned_files)} 个旧日志文件: {cleaned_files}")
    
    def set_log_level(self, level: int, logger_name: str = None):
        """动态调整日志级别
        
        Args:
            level: 新的日志级别 (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL)
            logger_name: 指定日志器名称，None表示调整根日志器
        """
        if logger_name:
            logger = logging.getLogger(logger_name)
        else:
            logger = logging.getLogger()
        
        old_level = logger.level
        logger.setLevel(level)
        
        # 同时调整所有处理器的级别
        for handler in logger.handlers:
            if not isinstance(handler, logging.StreamHandler) or handler.stream not in (sys.stdout, sys.stderr):
                # 不调整控制台处理器的级别，保持原有设置
                handler.setLevel(level)
        
        level_name = logging.getLevelName(level)
        old_level_name = logging.getLevelName(old_level)
        target = logger_name or "根日志器"
        
        logger.info(f"日志级别已调整: {target} {old_level_name} -> {level_name}")
    
    def set_temporary_log_level(self, level: int, logger_name: str = None):
        """临时调整日志级别（会保存原始级别用于恢复）
        
        Args:
            level: 临时日志级别
            logger_name: 指定日志器名称，None表示调整根日志器
        """
        if not hasattr(self, '_original_levels'):
            self._original_levels = {}
        
        target_name = logger_name or 'root'
        
        if logger_name:
            logger = logging.getLogger(logger_name)
        else:
            logger = logging.getLogger()
        
        # 保存原始级别
        if target_name not in self._original_levels:
            self._original_levels[target_name] = logger.level
        
        # 设置新级别
        self.set_log_level(level, logger_name)
        
        level_name = logging.getLevelName(level)
        target = logger_name or "根日志器"
        logger.info(f"临时调整日志级别: {target} -> {level_name} (可通过restore_log_level恢复)")
    
    def restore_log_level(self, logger_name: str = None):
        """恢复日志级别到调整前的状态
        
        Args:
            logger_name: 指定日志器名称，None表示恢复根日志器
        """
        if not hasattr(self, '_original_levels'):
            logging.warning("没有找到保存的原始日志级别")
            return
        
        target_name = logger_name or 'root'
        
        if target_name not in self._original_levels:
            logging.warning(f"没有找到 {target_name} 的原始日志级别")
            return
        
        original_level = self._original_levels[target_name]
        self.set_log_level(original_level, logger_name)
        
        # 清除保存的级别
        del self._original_levels[target_name]
        
        target = logger_name or "根日志器"
        level_name = logging.getLevelName(original_level)
        logging.info(f"已恢复日志级别: {target} -> {level_name}")
    
    def get_current_log_levels(self) -> dict:
        """获取当前所有日志器的级别信息
        
        Returns:
            dict: 日志器级别信息
        """
        levels_info = {}
        
        # 根日志器
        root_logger = logging.getLogger()
        levels_info['root'] = {
            'level': root_logger.level,
            'level_name': logging.getLevelName(root_logger.level),
            'handlers_count': len(root_logger.handlers)
        }
        
        # 其他已创建的日志器
        for name, logger in logging.Logger.manager.loggerDict.items():
            if isinstance(logger, logging.Logger):
                levels_info[name] = {
                    'level': logger.level,
                    'level_name': logging.getLevelName(logger.level),
                    'handlers_count': len(logger.handlers)
                }
        
        return levels_info


# 全局日志配置实例
logger_config = LoggerConfig()


def setup_system_logging(app_name: str = "lzwcai_mcp_sqlexecutor", 
                        log_level: int = logging.INFO) -> logging.Logger:
    """系统日志初始化快捷函数
    
    Args:
        app_name: 应用名称
        log_level: 日志级别
        
    Returns:
        logging.Logger: 根日志器
    """
    return logger_config.setup_logging(app_name, log_level)


def get_logger(name: str) -> logging.Logger:
    """获取日志器的快捷函数
    
    Args:
        name: 日志器名称
        
    Returns:
        logging.Logger: 日志器实例
    """
    return logger_config.get_module_logger(name)


def set_log_level(level: int, logger_name: str = None):
    """动态调整日志级别的快捷函数
    
    Args:
        level: 新的日志级别 (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL)
        logger_name: 指定日志器名称，None表示调整根日志器
    
    Examples:
        # 调整根日志器为DEBUG级别
        set_log_level(logging.DEBUG)
        
        # 调整特定模块日志器为WARNING级别
        set_log_level(logging.WARNING, "agent_ontology.core")
    """
    logger_config.set_log_level(level, logger_name)


def set_temporary_log_level(level: int, logger_name: str = None):
    """临时调整日志级别的快捷函数
    
    Args:
        level: 临时日志级别
        logger_name: 指定日志器名称，None表示调整根日志器
    
    Examples:
        # 临时调整为DEBUG级别进行调试
        set_temporary_log_level(logging.DEBUG)
        # ... 进行调试 ...
        # 恢复原始级别
        restore_log_level()
    """
    logger_config.set_temporary_log_level(level, logger_name)


def restore_log_level(logger_name: str = None):
    """恢复日志级别的快捷函数
    
    Args:
        logger_name: 指定日志器名称，None表示恢复根日志器
    """
    logger_config.restore_log_level(logger_name)


def get_current_log_levels() -> dict:
    """获取当前日志级别信息的快捷函数
    
    Returns:
        dict: 日志器级别信息
    
    Examples:
        levels = get_current_log_levels()
        print(f"根日志器级别: {levels['root']['level_name']}")
    """
    return logger_config.get_current_log_levels()


# 便捷的日志级别常量
class LogLevel:
    """日志级别常量类"""
    DEBUG = logging.DEBUG
    INFO = logging.INFO
    WARNING = logging.WARNING
    ERROR = logging.ERROR
    CRITICAL = logging.CRITICAL