# Copyright (c) 2025, JINGROW and contributors
# For license information, please see license.txt

"""
钩子执行器 - 执行钩子的便捷函数和类
支持同步/异步执行、错误处理、性能监控
"""

import logging
import time
import asyncio
from typing import Dict, List, Any, Optional, Callable
from .registry import registry

logger = logging.getLogger(__name__)


class HookExecutor:
    """
    钩子执行器 - 提供统一的钩子执行接口
    
    特性：
    - 同步/异步执行
    - 错误处理
    - 性能监控
    - 批量执行
    """
    
    @staticmethod
    def execute(
        hook_name: str,
        sender: Optional[str] = None,
        raise_on_error: bool = False,
        **kwargs
    ) -> List[Any]:
        """
        同步执行钩子
        
        :param hook_name: 钩子名称
        :param sender: 发送者类型
        :param raise_on_error: 是否在错误时抛出异常
        :param kwargs: 钩子参数
        :return: 所有处理器返回值的列表
        """
        start_time = time.time()
        
        try:
            results = registry.send(hook_name, sender=sender, **kwargs)
            
            elapsed = time.time() - start_time
            if elapsed > 0.1:  # 超过100ms记录警告
                logger.warning(f"钩子执行较慢: {hook_name} ({elapsed:.3f}s)")
            
            return results
            
        except Exception as e:
            logger.error(f"执行钩子失败: {hook_name} - {e}", exc_info=True)
            if raise_on_error:
                raise
            return []
    
    @staticmethod
    async def execute_async(
        hook_name: str,
        sender: Optional[str] = None,
        raise_on_error: bool = False,
        **kwargs
    ) -> List[Any]:
        """
        异步执行钩子
        
        :param hook_name: 钩子名称
        :param sender: 发送者类型
        :param raise_on_error: 是否在错误时抛出异常
        :param kwargs: 钩子参数
        :return: 所有处理器返回值的列表
        """
        start_time = time.time()
        
        try:
            results = await registry.send_async(hook_name, sender=sender, **kwargs)
            
            elapsed = time.time() - start_time
            if elapsed > 1:  # 超过1秒记录警告
                logger.warning(f"异步钩子执行较慢: {hook_name} ({elapsed:.3f}s)")
            
            return results
            
        except Exception as e:
            logger.error(f"异步执行钩子失败: {hook_name} - {e}", exc_info=True)
            if raise_on_error:
                raise
            return []
    
    @staticmethod
    def execute_batch(hooks: List[Dict[str, Any]], raise_on_error: bool = False) -> Dict[str, List[Any]]:
        """
        批量执行钩子
        
        :param hooks: 钩子列表，每个元素为 {"name": "...", "sender": "...", **kwargs}
        :param raise_on_error: 是否在错误时抛出异常
        :return: 执行结果字典 {hook_name: results}
        """
        results = {}
        
        for hook_config in hooks:
            hook_name = hook_config.pop('name')
            sender = hook_config.pop('sender', None)
            
            try:
                results[hook_name] = HookExecutor.execute(
                    hook_name,
                    sender=sender,
                    raise_on_error=raise_on_error,
                    **hook_config
                )
            except Exception as e:
                logger.error(f"批量执行钩子失败: {hook_name} - {e}")
                results[hook_name] = []
                if raise_on_error:
                    raise
        
        return results
    
    @staticmethod
    async def execute_batch_async(
        hooks: List[Dict[str, Any]],
        raise_on_error: bool = False
    ) -> Dict[str, List[Any]]:
        """
        异步批量执行钩子
        
        :param hooks: 钩子列表
        :param raise_on_error: 是否在错误时抛出异常
        :return: 执行结果字典
        """
        results = {}
        
        # 并行执行所有钩子
        tasks = []
        for hook_config in hooks:
            hook_name = hook_config['name']
            sender = hook_config.get('sender')
            kwargs = {k: v for k, v in hook_config.items() if k not in ('name', 'sender')}
            
            task = HookExecutor.execute_async(
                hook_name,
                sender=sender,
                raise_on_error=raise_on_error,
                **kwargs
            )
            tasks.append((hook_name, task))
        
        # 等待所有任务完成
        for hook_name, task in tasks:
            try:
                results[hook_name] = await task
            except Exception as e:
                logger.error(f"异步批量执行钩子失败: {hook_name} - {e}")
                results[hook_name] = []
                if raise_on_error:
                    raise
        
        return results


# 便捷函数
def execute_hook(
    hook_name: str,
    sender: Optional[str] = None,
    raise_on_error: bool = False,
    **kwargs
) -> List[Any]:
    """
    同步执行钩子（便捷函数）
    
    示例:
        results = execute_hook('page.User.on_update', sender='User', page=page_obj)
    """
    return HookExecutor.execute(hook_name, sender=sender, raise_on_error=raise_on_error, **kwargs)


async def execute_hook_async(
    hook_name: str,
    sender: Optional[str] = None,
    raise_on_error: bool = False,
    **kwargs
) -> List[Any]:
    """
    异步执行钩子（便捷函数）
    
    示例:
        results = await execute_hook_async('page.User.on_update', sender='User', page=page_obj)
    """
    return await HookExecutor.execute_async(
        hook_name,
        sender=sender,
        raise_on_error=raise_on_error,
        **kwargs
    )

