#!/usr/bin/env python
# -*- coding:utf-8 -*-
# ================================
# Author: nbyue
# Date: 2025/4/3 17:01
# File: enhanced_logger.py
# Desc: v1.3 20260317 EnhancedLogger 直接继承 Logger，可直接使用
# ================================

import logging
import os.path
import sys
import json
from pathlib import Path
from logging.handlers import TimedRotatingFileHandler
from typing import Dict


class EnhancedLogger(logging.Logger):
    """
    支持多处理器、配置文件、异常捕获的增强型日志记录器
    """
    # 单例模式缓存
    _instances = {}
    # 配置文件名称
    config_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "logging_config.json")

    def __new__(cls, name: str = "root", root_dir: str = None):
        if name not in cls._instances:
            cls._instances[name] = super().__new__(cls)
        return cls._instances[name]

    def __init__(self, name: str = "root", root_dir: str = None):
        # 避免重复初始化
        if hasattr(self, '_initialized'):
            return
            
        # 初始化父类 Logger
        super().__init__(name)
        
        self.config = self._load_config()
        self._root_dir = Path(root_dir) if root_dir else Path(self.config.get("root_dir", "./"))
        self._log_dir = self._root_dir / Path(self.config["log_dir"])
        self._setup_logger()
        self._initialized = True

    @classmethod
    def create_custom_logger(cls, name: str, config=None):
        """
        创建自定义配置的日志记录器

        Args:
            name: logger 名称
            config: 配置字典，包含：
                - root_dir: 日志根目录
                - log_dir: 子目录名
                - filename: 日志文件名
                - level: 日志级别 (默认 INFO)
                - when: 滚动时间间隔 (默认 midnight)
                - backup_count: 备份数量 (默认 7)
                - format_type: 格式类型 standard/json (默认 standard)
                - verbose: 是否显示详细日志 (默认 False)
                - enable_console: 是否启用控制台输出 (默认 False)

        Example:
            >>> # 创建 MySQL 采集日志（简洁模式）
            >>> logger = EnhancedLogger.create_custom_logger(
                    "mysql_collection",
                    {
                        "root_dir": "/root/logs",
                        "log_dir": "mysqlCollectionLogs",
                        "filename": "mysql_collection.log",
                        "level": "INFO",
                        "when": "midnight",
                        "backup_count": 7
                    }
                )

            >>> # 创建调试日志（详细模式）
            >>> logger = EnhancedLogger.create_custom_logger(
                    "debug_app",
                    {
                        "root_dir": "/root/logs",
                        "log_dir": "debug",
                        "filename": "debug.log",
                        "verbose": True
                    }
                )

        Returns:
            EnhancedLogger 实例（可直接使用）
        """
        if config is None:
            config = {}
        instance = cls.__new__(cls, name)
        instance._custom_init(name, config)
        return instance
    
    def _custom_init(self, name: str, config: Dict):
        """自定义初始化"""
        if hasattr(self, '_initialized'):
            return
            
        # 初始化父类 Logger
        super().__init__(name)
        
        verbose = config.get("verbose", False)

        self.config = {
            "log_level": config.get("level", "INFO"),
            "log_dir": config.get("log_dir", "logs"),
            "verbose": verbose,
            "formats": {
                "standard": "%(asctime)s | %(levelname)-8s | %(message)s" if not verbose
                else "%(asctime)s | %(name)s | %(levelname)-8s | %(module)s:%(lineno)d - %(message)s",
                "json": "{'timestamp': '%(asctime)s', 'level': '%(levelname)s', 'message': '%(message)s'}"
            },
            "handlers": {
                "console": {
                    "enabled": config.get("enable_console", False),
                    "level": config.get("level", "INFO")
                },
                "file": {
                    "enabled": True,
                    "filename": config.get("filename", "app.log"),
                    "when": config.get("when", "midnight"),
                    "backup_count": config.get("backup_count", 7),
                    "level": config.get("level", "INFO")
                }
            }
        }

        format_type = config.get("format_type", "standard")
        if format_type == "json":
            self.config["formats"]["standard"] = self.config["formats"]["json"]

        self._root_dir = Path(config.get("root_dir", "./"))
        self._log_dir = self._root_dir / Path(self.config["log_dir"])
        self._setup_logger()
        self._initialized = True

    def _load_config(self) -> Dict:
        """加载日志配置文件"""
        default_config = {
            "log_level": "INFO",
            "root_dir": "/root",
            "log_dir": "logs",
            "verbose": False,
            "formats": {
                "standard": "%(asctime)s | %(levelname)-8s | %(message)s",
                "json": "{'timestamp': '%(asctime)s', 'level': '%(levelname)s', 'message': '%(message)s'}"
            },
            "handlers": {
                "console": {
                    "enabled": False,
                    "level": "INFO"
                },
                "file": {
                    "enabled": True,
                    "filename": "app.log",
                    "when": "midnight",
                    "backup_count": 7,
                    "level": "INFO"
                }
            }
        }

        try:
            with open(self.config_path) as f:
                return json.load(f)
        except (FileNotFoundError, json.JSONDecodeError) as e:
            return default_config

    def _setup_logger(self):
        """配置日志处理器"""
        # 清空已有处理器（防止重复）
        self.handlers = []

        # 设置日志级别
        self.setLevel(self.config["log_level"].upper())

        # 创建日志目录
        self._log_dir.mkdir(exist_ok=True, parents=True)

        # 初始化处理器
        self._init_console_handler()
        self._init_file_handlers()

    def _init_console_handler(self):
        """控制台输出处理器"""
        if self.config["handlers"]["console"]["enabled"]:
            handler = logging.StreamHandler(sys.stdout)
            handler.setLevel(self.config["handlers"]["console"]["level"].upper())
            handler.setFormatter(self._get_formatter('standard'))
            self._add_handler(handler)

    def _init_file_handlers(self):
        """文件处理器"""
        # 主日志文件（按时间滚动）
        if self.config["handlers"]["file"]["enabled"]:
            file_path = self._log_dir / self.config["handlers"]["file"]["filename"]
            handler = TimedRotatingFileHandler(
                filename=str(file_path),
                when=self.config["handlers"]["file"]["when"],
                backupCount=self.config["handlers"]["file"]["backup_count"],
                encoding='utf-8'
            )
            handler.setLevel(self.config["handlers"]["file"]["level"].upper())
            handler.setFormatter(self._get_formatter('standard'))
            self._add_handler(handler)

    def _get_formatter(self, format_type: str) -> logging.Formatter:
        """获取格式化器"""
        fmt = self.config["formats"].get(format_type, "%(message)s")
        if format_type == 'json':
            return JsonFormatter(fmt)
        return logging.Formatter(fmt)

    def _add_handler(self, handler: logging.Handler):
        """添加处理器并去重"""
        if not any(isinstance(h, type(handler)) for h in self.handlers):
            self.addHandler(handler)

    @staticmethod
    def catch_exceptions(func):
        """自动捕获并记录异常的装饰器"""

        def wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except Exception as e:
                self = args[0] if args and hasattr(args[0], 'logger') else EnhancedLogger()
                self.logger.exception(f"Exception in {func.__name__}: {str(e)}")
                raise

        return wrapper


class JsonFormatter(logging.Formatter):
    """生成 JSON 格式的日志"""

    def format(self, record):
        log_record = {
            'timestamp': self.formatTime(record),
            'level': record.levelname,
            'message': record.getMessage(),
            'module': record.module,
            'line': record.lineno
        }
        if record.exc_info:
            log_record['exception'] = self.formatException(record.exc_info)
        return json.dumps(log_record, ensure_ascii=False)


def create_logger(name: str, config: Dict = None) -> EnhancedLogger:
    """
    快速获取自定义配置的 logger

    Args:
        name: logger 名称
        config: 配置字典（可选，不传则使用默认配置）
        
    Example:
        >>> # 方式 1：使用自定义配置
        >>> logger = create_logger(
                "mysql_collection",
                {
                    "root_dir": "/root/logs",
                    "log_dir": "mysqlCollectionLogs",
                    "filename": "mysql_collection.log"
                }
            )
        
        >>> # 方式 2：使用默认配置（config=None 或不传）
        >>> logger = create_logger("default_app")
        
    Returns:
        EnhancedLogger 实例（可直接调用 info/error 等方法）
    """
    return EnhancedLogger.create_custom_logger(name, config)
