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

"""
Signal 系统 - 支持优先级、条件过滤、类型提示
"""

import logging
import asyncio
from typing import Callable, Dict, List, Any, Optional, Union
from dataclasses import dataclass, field
from functools import wraps
from enum import IntEnum

logger = logging.getLogger(__name__)


class Priority(IntEnum):
    """钩子执行优先级"""
    LOWEST = 100
    LOW = 75
    NORMAL = 50
    HIGH = 25
    HIGHEST = 1


@dataclass
class HookHandler:
    """钩子处理器"""
    handler: Callable
    sender: Optional[str] = None  # 发送者类型，如 "User", None 表示所有
    priority: Priority = Priority.NORMAL
    condition: Optional[Callable] = None  # 条件函数，返回 True 才执行
    once: bool = False  # 是否只执行一次
    weak: bool = False  # 弱引用（暂不支持）
    _executed: bool = False  # 是否已执行（用于 once 模式）

    def __call__(self, *args, **kwargs) -> Any:
        """执行处理器"""
        if self.once and self._executed:
            return None
        
        # 检查条件
        if self.condition:
            try:
                if not self.condition(*args, **kwargs):
                    return None
            except Exception as e:
                logger.warning(f"钩子条件检查失败: {e}")
                return None
        
        try:
            result = self.handler(*args, **kwargs)
            if self.once:
                self._executed = True
            return result
        except Exception as e:
            logger.error(f"钩子处理器执行失败: {e}", exc_info=True)
            raise

    async def __acall__(self, *args, **kwargs) -> Any:
        """异步执行处理器"""
        if self.once and self._executed:
            return None
        
        # 检查条件
        if self.condition:
            try:
                if not self.condition(*args, **kwargs):
                    return None
            except Exception as e:
                logger.warning(f"钩子条件检查失败: {e}")
                return None
        
        try:
            if asyncio.iscoroutinefunction(self.handler):
                result = await self.handler(*args, **kwargs)
            else:
                result = self.handler(*args, **kwargs)
            
            if self.once:
                self._executed = True
            return result
        except Exception as e:
            logger.error(f"异步钩子处理器执行失败: {e}", exc_info=True)
            raise


class Signal:
    """
    信号类 - 类似 Django Signal
    
    用法：
        # 定义信号
        page_saved = Signal()
        
        # 连接处理器
        @page_saved.connect(sender='User', priority=Priority.HIGH)
        def handle_page_saved(page, created, **kwargs):
            print(f"Page saved: {page.name}")
        
        # 发送信号
        page_saved.send(sender='User', page=page, created=True)
    """
    
    def __init__(self, providing_args: Optional[List[str]] = None):
        """
        初始化信号
        
        :param providing_args: 提供的参数列表（用于文档和类型检查）
        """
        self.providing_args = providing_args or []
        self._handlers: List[HookHandler] = []
        self._handlers_by_sender: Dict[str, List[HookHandler]] = {}
    
    def connect(
        self,
        handler: Optional[Callable] = None,
        *,
        sender: Optional[str] = None,
        priority: Priority = Priority.NORMAL,
        condition: Optional[Callable] = None,
        once: bool = False,
        weak: bool = False
    ) -> Union[Callable, Callable]:
        """
        连接处理器（可用作装饰器或直接调用）
        
        :param handler: 处理器函数
        :param sender: 发送者类型
        :param priority: 优先级
        :param condition: 条件函数
        :param once: 是否只执行一次
        :param weak: 弱引用（暂不支持）
        """
        if handler is None:
            # 用作装饰器
            def decorator(func: Callable) -> Callable:
                self.connect(
                    func,
                    sender=sender,
                    priority=priority,
                    condition=condition,
                    once=once,
                    weak=weak
                )
                return func
            return decorator
        
        # 注册处理器
        hook_handler = HookHandler(
            handler=handler,
            sender=sender,
            priority=priority,
            condition=condition,
            once=once,
            weak=weak
        )
        
        if sender:
            if sender not in self._handlers_by_sender:
                self._handlers_by_sender[sender] = []
            self._handlers_by_sender[sender].append(hook_handler)
        else:
            self._handlers.append(hook_handler)
        
        # 按优先级排序（优先级越小越先执行）
        if sender:
            self._handlers_by_sender[sender].sort(key=lambda h: h.priority)
        self._handlers.sort(key=lambda h: h.priority)
        
        logger.debug(f"注册钩子处理器: {handler.__name__} (sender={sender}, priority={priority})")
        return handler
    
    def disconnect(self, handler: Callable, sender: Optional[str] = None) -> None:
        """断开处理器连接"""
        if sender:
            handlers = self._handlers_by_sender.get(sender, [])
            self._handlers_by_sender[sender] = [h for h in handlers if h.handler != handler]
        else:
            self._handlers = [h for h in self._handlers if h.handler != handler]
    
    def send(self, sender: Optional[str] = None, **kwargs) -> List[Any]:
        """
        同步发送信号
        
        :param sender: 发送者类型
        :param kwargs: 信号参数
        :return: 所有处理器返回值的列表
        """
        results = []
        
        # 获取所有相关处理器
        handlers = self._get_handlers(sender)
        
        for handler in handlers:
            try:
                result = handler(**kwargs)
                if result is not None:
                    results.append(result)
            except Exception as e:
                logger.error(f"钩子处理器执行失败: {e}", exc_info=True)
                # 继续执行其他处理器，除非是严重错误
        
        return results
    
    async def send_async(self, sender: Optional[str] = None, **kwargs) -> List[Any]:
        """
        异步发送信号
        
        :param sender: 发送者类型
        :param kwargs: 信号参数
        :return: 所有处理器返回值的列表
        """
        results = []
        
        # 获取所有相关处理器
        handlers = self._get_handlers(sender)
        
        for handler in handlers:
            try:
                result = await handler.__acall__(**kwargs)
                if result is not None:
                    results.append(result)
            except Exception as e:
                logger.error(f"异步钩子处理器执行失败: {e}", exc_info=True)
                # 继续执行其他处理器
        
        return results
    
    def _get_handlers(self, sender: Optional[str] = None) -> List[HookHandler]:
        """获取相关处理器列表（已按优先级排序）"""
        handlers = []
        
        # 添加通用处理器（sender=None）
        handlers.extend(self._handlers)
        
        # 添加特定 sender 的处理器
        if sender:
            handlers.extend(self._handlers_by_sender.get(sender, []))
        
        # 重新按优先级排序（因为合并了通用和特定的）
        handlers.sort(key=lambda h: h.priority)
        
        return handlers
    
    def has_listeners(self, sender: Optional[str] = None) -> bool:
        """检查是否有监听器"""
        if sender:
            return len(self._handlers) > 0 or len(self._handlers_by_sender.get(sender, [])) > 0
        return len(self._handlers) > 0
    
    def clear(self) -> None:
        """清空所有处理器"""
        self._handlers.clear()
        self._handlers_by_sender.clear()


# 便捷函数：创建信号
def signal(providing_args: Optional[List[str]] = None) -> Signal:
    """创建新的信号"""
    return Signal(providing_args=providing_args)

