import traceback
from typing import List, Any

from app.db.systemconfigs import SystemConfigs
from app.helper.module import ModuleHelper
from app.log import logger
from app.utils.singleton import Singleton


class PluginManager(metaclass=Singleton):
    """
    插件管理器
    """
    systemconfigs: SystemConfigs = None

    # 插件列表
    _plugins: dict = {}
    # 运行态插件列表
    _running_plugins: dict = {}
    # 配置Key
    _config_key: str = "plugin.%s"

    def __init__(self):
        self.init_config()

    def init_config(self):
        self.systemconfigs = SystemConfigs()
        # 停止已有插件
        self.stop()
        # 启动插件
        self.start()

    def start(self):
        """
        启动
        """
        # 加载插件
        self.__load_plugins()

    def stop(self):
        """
        停止
        """
        # 停止所有插件
        self.__stop_plugins()

    def __load_plugins(self):
        """
        加载所有插件
        """
        # 扫描插件目录
        plugins = ModuleHelper.load(
            "app.plugins",
            filter_func=lambda _, obj: hasattr(obj, 'init_plugin')
        )
        # 排序
        plugins.sort(key=lambda x: x.plugin_order if hasattr(x, "plugin_order") else 0)
        self._running_plugins = {}
        self._plugins = {}
        for plugin in plugins:
            plugin_id = plugin.__name__
            self._plugins[plugin_id] = plugin
            # 生成实例
            self._running_plugins[plugin_id] = plugin()
            # 初始化配置
            self.reload_plugin(plugin_id)
            logger.info(f"Plugin Loaded：{plugin.__name__}")

    def reload_plugin(self, pid: str):
        """
        生效插件配置
        """
        if not pid:
            return
        if not self._running_plugins.get(pid):
            return
        if hasattr(self._running_plugins[pid], "init_plugin"):
            try:
                self._running_plugins[pid].init_plugin(self.get_plugin_config(pid))
                logger.debug(f"生效插件配置：{pid}")
            except Exception as err:
                logger.error(f"加载插件 {pid} 出错：{err} - {traceback.format_exc()}")

    def __stop_plugins(self):
        """
        停止所有插件
        """
        for plugin in self._running_plugins.values():
            if hasattr(plugin, "stop"):
                plugin.stop()

    def get_plugin_config(self, pid: str) -> dict:
        """
        获取插件配置
        """
        if not self._plugins.get(pid):
            return {}
        return self.systemconfigs.get(self._config_key % pid) or {}

    def save_plugin_config(self, pid: str, conf: dict) -> bool:
        """
        保存插件配置
        """
        if not self._plugins.get(pid):
            return False
        return self.systemconfigs.set(self._config_key % pid, conf)

    def get_plugin_commands(self) -> List[dict]:
        """
        获取插件命令
        [{
            "cmd": "/xx",
            "event": EventType.xx,
            "desc": "xxxx",
            "data": {}
        }]
        """
        ret_commands = []
        for _, plugin in self._running_plugins.items():
            if hasattr(plugin, "get_command"):
                ret_commands.append(plugin.get_command())
        return ret_commands

    def run_plugin_method(self, pid: str, method: str, *args, **kwargs) -> Any:
        """
        运行插件方法
        """
        if not self._running_plugins.get(pid):
            return None
        if not hasattr(self._running_plugins[pid], method):
            return None
        return getattr(self._running_plugins[pid], method)(*args, **kwargs)
