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

"""
钩子注册表 - 管理所有钩子信号
支持按名称注册和获取钩子
"""

import logging
from typing import Dict, Optional, Any
from .signal import Signal, Priority

logger = logging.getLogger(__name__)


class HookRegistry:
    """
    钩子注册表 - 全局单例
    
    用法：
        # 注册钩子
        registry.register('page.saved', Signal())
        
        # 获取钩子
        page_saved = registry.get('page.saved')
        
        # 连接处理器
        @page_saved.connect(sender='User')
        def handle(page, **kwargs):
            pass
        
        # 发送信号
        registry.send('page.saved', sender='User', page=page)
    """
    
    _instance = None
    
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance._signals: Dict[str, Signal] = {}
            cls._instance._initialized = False
        return cls._instance
    
    def register(self, name: str, signal: Optional[Signal] = None) -> Signal:
        """
        注册钩子（如果不存在则创建）
        
        :param name: 钩子名称，如 "page.saved", "page.before_insert"
        :param signal: 信号对象，如果为 None 则创建新信号
        :return: Signal 对象
        """
        if name not in self._signals:
            if signal is None:
                signal = Signal()
            self._signals[name] = signal
            logger.debug(f"注册钩子: {name}")
        
        return self._signals[name]
    
    def get(self, name: str, default: Optional[Signal] = None) -> Optional[Signal]:
        """获取钩子"""
        return self._signals.get(name, default)
    
    def send(self, name: str, sender: Optional[str] = None, **kwargs) -> list:
        """
        同步发送钩子
        
        :param name: 钩子名称
        :param sender: 发送者类型
        :param kwargs: 信号参数
        :return: 所有处理器返回值的列表
        """
        signal = self.get(name)
        if signal is None:
            logger.warning(f"钩子不存在: {name}")
            return []
        
        return signal.send(sender=sender, **kwargs)
    
    async def send_async(self, name: str, sender: Optional[str] = None, **kwargs) -> list:
        """
        异步发送钩子
        
        :param name: 钩子名称
        :param sender: 发送者类型
        :param kwargs: 信号参数
        :return: 所有处理器返回值的列表
        """
        signal = self.get(name)
        if signal is None:
            logger.warning(f"钩子不存在: {name}")
            return []
        
        return await signal.send_async(sender=sender, **kwargs)
    
    def connect(
        self,
        name: str,
        handler: Any = None,
        *,
        sender: Optional[str] = None,
        priority: Priority = Priority.NORMAL,
        condition: Optional[Any] = None,
        once: bool = False
    ) -> Any:
        """
        连接处理器到钩子（可用作装饰器）
        
        :param name: 钩子名称
        :param handler: 处理器函数（用作装饰器时可省略）
        :param sender: 发送者类型
        :param priority: 优先级
        :param condition: 条件函数
        :param once: 是否只执行一次
        """
        signal = self.register(name)
        
        if handler is None:
            # 用作装饰器
            return signal.connect(
                sender=sender,
                priority=priority,
                condition=condition,
                once=once
            )
        
        # 直接连接
        return signal.connect(
            handler,
            sender=sender,
            priority=priority,
            condition=condition,
            once=once
        )
    
    def disconnect(self, name: str, handler: Any, sender: Optional[str] = None) -> None:
        """断开处理器连接"""
        signal = self.get(name)
        if signal:
            signal.disconnect(handler, sender=sender)
    
    def has_listeners(self, name: str, sender: Optional[str] = None) -> bool:
        """检查钩子是否有监听器"""
        signal = self.get(name)
        if signal is None:
            return False
        return signal.has_listeners(sender)
    
    def clear(self, name: Optional[str] = None) -> None:
        """清空钩子（如果 name 为 None 则清空所有）"""
        if name is None:
            self._signals.clear()
            logger.debug("清空所有钩子")
        elif name in self._signals:
            self._signals[name].clear()
            logger.debug(f"清空钩子: {name}")
    
    def list_all(self) -> list:
        """列出所有已注册的钩子名称"""
        return list(self._signals.keys())


# 全局注册表实例
registry = HookRegistry()

