import importlib
import inspect
from typing import Any, Iterable

from typing import TYPE_CHECKING

from .type import PluginPath, PluginConfig, PluginSpec
if TYPE_CHECKING:
    from ..core.bot import Bot

def load_plugin(bot: "Bot", target: PluginPath, config: PluginConfig | None) -> Any:
    """加载单个插件。
     Args:
         target: 插件目标字符串：
             - 'pkg.mod'             -> 模块级插件，模块中需定义 setup(bot, **config)
             - 'pkg.mod:ClassName'   -> 类式插件，类需定义 setup(self, bot)
         bot: 当前 Bot 实例
         config: 传给插件的配置字典

     Returns:
         插件对象（模块对象或类实例）。
     """
    config = dict(config or {})
    if ":" in target:
        module_name, cls_name = target.split(":", 1)
    else:
        module_name, cls_name = target, None
    module = importlib.import_module(module_name)
    if cls_name is None:
        setup = getattr(module, '__setup__', None)
        if callable(setup):
            setup(bot, **config)
        return module
    else:
        cls = getattr(module, cls_name)
        if callable(cls):
            instance = cls(**config)
            _replace_instance_handlers(instance)
            setup = getattr(instance, '__setup__', None)
            if callable(setup):
                setup(bot)
            return instance
        raise RuntimeError(f"不支持的插件 target: {target!r}")

def load_plugins(bot: "Bot", specs: Iterable[PluginSpec]):
    loaded = []
    for spec in specs:
        if isinstance(spec, str):
            target, config = spec, None
        else:
            target, config = spec
        plugin = load_plugin(bot, target, config)
        loaded.append(plugin)
    return loaded

def _replace_instance_handlers(instance: Any):
    """将类定义阶段注册的函数 handler 替换为绑定到实例的方法。

    思路：
      - 找到插件类中所有带 `_condition` 属性的函数（被条件装饰器修饰过）
      - 在全局 handler 注册表中，把对应的函数替换为 `instance.<method>`
    """
    from asa.core.deco import handler
    cls = instance.__class__
    func_map: dict[Any, str] = {}
    for name, method in inspect.getmembers(cls, predicate=inspect.isfunction):
        if hasattr(method, "_condition"):
            func_map[method] = name
    if not func_map:
        return
    entries = handler.get_handlers()
    for entry in entries:
        method = entry.get("func")
        if method in func_map:
            method_name = func_map[method]
            bound_method = getattr(instance, method_name)
            entry["func"] = bound_method

__all__ = ["load_plugin", "load_plugins", "PluginSpec", "PluginPath", "PluginConfig"]