# 导入logging模块，用于记录钩子系统运行过程中的日志（如注册信息、错误信息等）
import logging 

# 创建当前模块的日志记录器，日志名称与模块绑定，便于区分不同组件的日志输出
logger = logging.getLogger(__name__)

# 全局钩子存储字典，用于保存所有注册的钩子及其对应的回调函数
# 键：钩子名称（字符串，如"article_create"）
# 值：回调函数列表（所有注册到该钩子的可调用对象将按注册顺序存储）
_hooks = {}


def register(hook_name: str, callback: callable):
    """
    注册一个钩子回调函数，将其添加到指定钩子名称对应的回调列表中
    
    核心作用：建立"钩子名称"与"处理逻辑（回调函数）"的映射关系，
    使后续触发钩子时能自动执行所有注册的回调
    
    :param hook_name: 钩子名称（字符串），需与触发时使用的名称一致（如ARTICLE_CREATE）
    :param callback: 可调用对象（函数、方法等），当钩子被触发时会执行此对象
                     回调函数的参数需与钩子触发时传递的参数匹配
    """
    # 若钩子名称尚未在全局字典中，初始化一个空列表用于存储回调
    if hook_name not in _hooks:
        _hooks[hook_name] = []
    # 将回调函数添加到对应钩子的列表中（按注册顺序存储，触发时也按此顺序执行）
    _hooks[hook_name].append(callback)
    # 记录DEBUG级日志，说明钩子注册成功（包含钩子名称和回调函数名，便于调试）
    logger.debug(f"Registered hook '{hook_name}' with callback '{callback.__name__}'")


def run_action(hook_name: str, *args, **kwargs):
    """
    执行指定名称的"动作钩子（Action Hook）"，按注册顺序调用所有关联的回调函数
    
    动作钩子特性：用于触发一系列操作，不关注返回值，仅执行回调逻辑
    典型场景：文章创建后发送通知、记录日志等（执行动作但无需修改数据）
    
    :param hook_name: 要触发的钩子名称（需已被注册过）
    :param *args: 传递给回调函数的位置参数（可变参数，根据钩子场景定义）
    :param **kwargs: 传递给回调函数的关键字参数（可变参数，根据钩子场景定义）
    """
    # 检查该钩子是否有已注册的回调函数
    if hook_name in _hooks:
        # 记录DEBUG级日志，说明开始执行该动作钩子
        logger.debug(f"Running action hook '{hook_name}'")
        # 按注册顺序遍历所有回调函数并执行
        for callback in _hooks[hook_name]:
            try:
                # 传递位置参数和关键字参数给回调函数
                callback(*args, **kwargs)
            except Exception as e:
                # 若回调执行出错，记录ERROR级日志（包含详细异常信息）
                # exc_info=True 会在日志中附带堆栈跟踪，便于排查错误
                logger.error(
                    f"Error running action hook '{hook_name}' callback '{callback.__name__}': {e}",
                    exc_info=True
                )


def apply_filters(hook_name: str, value, *args, **kwargs):
    """
    执行指定名称的"过滤钩子（Filter Hook）"，通过回调函数链式处理初始值并返回最终结果
    
    过滤钩子特性：用于对数据进行加工处理，每个回调函数接收上一个函数的输出作为输入，
    最终返回经过所有回调处理后的值
    典型场景：文章内容过滤敏感词、格式化文本等（修改数据并返回新值）
    
    :param hook_name: 要触发的钩子名称（需已被注册过）
    :param value: 初始值（需要被过滤/处理的数据，如文章内容字符串）
    :param *args: 传递给回调函数的额外位置参数
    :param **kwargs: 传递给回调函数的额外关键字参数
    :return: 经过所有回调函数处理后的最终值
    """
    # 检查该钩子是否有已注册的回调函数
    if hook_name in _hooks:
        # 记录DEBUG级日志，说明开始执行该过滤钩子
        logger.debug(f"Applying filter hook '{hook_name}'")
        # 按注册顺序遍历所有回调函数，链式处理初始值
        for callback in _hooks[hook_name]:
            try:
                # 调用回调函数，将当前值和额外参数传入，更新值为回调返回的结果
                value = callback(value, *args, **kwargs)
            except Exception as e:
                # 若回调执行出错，记录ERROR级日志（包含详细异常信息）
                logger.error(
                    f"Error applying filter hook '{hook_name}' callback '{callback.__name__}': {e}",
                    exc_info=True
                )
    # 返回经过所有过滤处理后的最终值
    return value