
from functools import wraps
import time
from time import perf_counter
import logging
from logging.handlers import RotatingFileHandler
from typing import Callable, Any


# 配置日志记录器
def configure_logger(
    logger_name: str = "app",
    log_level: int = logging.INFO,
    log_file: str = "app.log",
    max_bytes: int = 10 * 1024 * 1024,  # 10MB
    backup_count: int = 5,
    console_output: bool = False
) -> logging.Logger:
    """
    配置应用程序日志记录器

    参数:
        logger_name: 日志记录器名称
        log_level: 日志记录级别
        log_file: 日志文件路径
        max_bytes: 单个日志文件最大字节数
        backup_count: 保留的备份文件数量
        console_output: 是否同时输出到控制台
    """
    logger = logging.getLogger(logger_name)
    logger.setLevel(log_level)

    # 避免重复添加handler
    if logger.handlers:
        return logger

    # 文件处理器配置
    file_handler = RotatingFileHandler(
        filename = log_file,
        maxBytes = max_bytes,
        backupCount = backup_count,
        encoding = "utf-8",
        delay=True  # 延迟打开文件直到实际写入
    )
    file_formatter = logging.Formatter(
        "[%(asctime)s] %(levelname)-8s %(module)s:%(lineno)d - %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S"
    )
    file_handler.setFormatter(file_formatter)
    logger.addHandler(file_handler)

    # 控制台处理器（可选）
    if console_output:
        console_handler = logging.StreamHandler()
        console_handler.setLevel(logging.WARNING)  # 控制台只显示警告及以上
        console_formatter = logging.Formatter(
            "%(levelname)-8s %(message)s"
        )
        console_handler.setFormatter(console_formatter)
        logger.addHandler(console_handler)

    return logger

def log(
    logger_name: str = "agent",
    log_file: str = "app.log",
    level: int = logging.INFO,
    log_args: bool = True,
    log_return: bool = True,
    max_arg_length: int = 500,
    max_result_length: int = 500,
    log_exceptions: bool = True,
    enable: bool = True
) -> Callable:
    """
    增强型日志装饰器

    参数:
        logger_name: 使用的日志记录器名称
        level: 日志记录级别
        log_args: 是否记录函数参数
        log_return: 是否记录返回值
        max_arg_length: 参数最大记录长度
        max_result_length: 结果最大记录长度
        log_exceptions: 是否记录异常信息
        enable: 是否启用日志记录
    """
    def decorator(func: Callable) -> Callable:
        @wraps(func)
        def wrapper(*args, **kwargs) -> Any:
            # 快速返回路径：禁用日志时
            if not enable:
                return func(*args, **kwargs)

            logger = logging.getLogger(logger_name)
            # 初始化日志记录器（如果尚未配置）
            if not logger.handlers:
                configure_logger(logger_name, level, log_file)

            # 构建日志元数据
            func_name = func.__qualname__
            module_name = func.__module__
            if module_name != "__main__":
                func_name = f"{module_name}.{func_name}"

            # 参数处理
            args_repr = []
            if log_args:
                try:
                    # 参数安全处理
                    args_repr = [
                        repr(arg)[:max_arg_length] + ("..." if len(repr(arg)) > max_arg_length else "")
                        for arg in args
                    ]
                    kwargs_repr = [
                        f"{k}={repr(v)[:max_arg_length]}" + ("..." if len(repr(v)) > max_arg_length else "")
                        for k, v in kwargs.items()
                    ]
                    all_args = ", ".join(args_repr + kwargs_repr)
                except Exception as e:
                    all_args = f"[参数序列化失败: {str(e)}]"
                    logger.warning("参数记录失败", exc_info=True)
            else:
                all_args = "..."

            # 记录开始信息
            start_time = perf_counter()
            logger.log(level, f"调用函数 {func_name}({all_args})")

            try:
                result = func(*args, **kwargs)
                duration = perf_counter() - start_time

                # 返回值处理
                return_repr = ""
                if log_return:
                    try:
                        result_repr = repr(result)
                        if len(result_repr) > max_result_length:
                            return_repr = result_repr[:max_result_length] + "..."
                        else:
                            return_repr = result_repr
                    except Exception as e:
                        return_repr = f"[结果序列化失败: {str(e)}]"
                        logger.warning("结果记录失败", exc_info=True)

                logger.log(
                    level,
                    f"成功执行函数 {func_name} [耗时: {duration:.4f}s] → {return_repr}"
                )
                return result

            except Exception as e:
                duration = perf_counter() - start_time
                if log_exceptions:
                    logger.error(
                        f"函数执行失败 {func_name} [耗时: {duration:.4f}s] | "
                        f"异常类型: {type(e).__name__}, 异常信息: {str(e)}",
                        exc_info=logger.isEnabledFor(logging.DEBUG)
                    )
                raise
        return wrapper
    return decorator
