"""动态插件加载器"""

import importlib
import importlib.util
import sys
from typing import Dict, List, Optional, Type
from pathlib import Path

from playwright.sync_api import Page

from .plugin_base import PluginBase
from ..reference import MODULEDATA, INFO


class PluginLoader:
    """动态插件加载器

    从指定目录或模块加载插件。
    """

    def __init__(self, page: Page = None):
        """初始化加载器

        Args:
            page: Playwright Page 实例
        """
        self._page = page
        self._plugins: Dict[str, PluginBase] = {}
        self._plugin_paths: List[Path] = []

    def add_plugin_path(self, path: str) -> None:
        """添加插件搜索路径

        Args:
            path: 插件目录路径
        """
        plugin_path = Path(path)
        if plugin_path.exists() and plugin_path.is_dir():
            self._plugin_paths.append(plugin_path)
            INFO(f"添加插件路径: {plugin_path}")

    def load_from_path(self, path: str) -> Optional[PluginBase]:
        """从路径加载单个插件

        Args:
            path: 插件目录或模块路径

        Returns:
            PluginBase: 加载的插件实例
        """
        plugin_path = Path(path)

        if plugin_path.is_dir():
            # 目录形式的插件
            return self._load_from_directory(plugin_path)
        elif plugin_path.is_file() and plugin_path.suffix == '.py':
            # 单文件插件
            return self._load_from_file(plugin_path)

        return None

    def _load_from_directory(self, directory: Path) -> Optional[PluginBase]:
        """从目录加载插件

        目录结构:
        plugin_name/
        ├── __init__.py
        ├── plugin_name_plugin.py  (包含插件类)
        ├── my.ini                 (可选配置)
        └── elementData/
            └── elementData.yaml   (可选元素数据)

        Args:
            directory: 插件目录

        Returns:
            PluginBase: 插件实例
        """
        plugin_name = directory.name

        # 查找插件主文件
        plugin_file = directory / f"{plugin_name}_plugin.py"
        if not plugin_file.exists():
            # 尝试其他命名
            plugin_files = list(directory.glob("*_plugin.py"))
            if plugin_files:
                plugin_file = plugin_files[0]
            else:
                INFO(f"未找到插件主文件: {directory}", "WARNING")
                return None

        # 加载模块
        spec = importlib.util.spec_from_file_location(plugin_name, plugin_file)
        if spec is None or spec.loader is None:
            return None

        module = importlib.util.module_from_spec(spec)
        sys.modules[plugin_name] = module
        spec.loader.exec_module(module)

        # 查找插件类
        plugin_class = self._find_plugin_class(module)
        if not plugin_class:
            INFO(f"未找到 PluginBase 子类: {plugin_file}", "WARNING")
            return None

        # 创建实例
        plugin = plugin_class(self._page)

        # 加载配置
        config_file = directory / "my.ini"
        if config_file.exists():
            plugin.load_config_from_file(str(config_file))

        # 加载元素数据
        element_data_file = directory / "elementData" / "elementData.yaml"
        if element_data_file.exists():
            plugin.load_element_data_from_file(str(element_data_file))

        # 初始化
        plugin.initialize()

        self._plugins[plugin.name] = plugin
        INFO(f"加载插件: {plugin}")

        return plugin

    def _load_from_file(self, file_path: Path) -> Optional[PluginBase]:
        """从单文件加载插件

        Args:
            file_path: 插件文件路径

        Returns:
            PluginBase: 插件实例
        """
        plugin_name = file_path.stem

        spec = importlib.util.spec_from_file_location(plugin_name, file_path)
        if spec is None or spec.loader is None:
            return None

        module = importlib.util.module_from_spec(spec)
        sys.modules[plugin_name] = module
        spec.loader.exec_module(module)

        plugin_class = self._find_plugin_class(module)
        if not plugin_class:
            INFO(f"未找到 PluginBase 子类: {file_path}", "WARNING")
            return None

        plugin = plugin_class(self._page)
        plugin.initialize()

        self._plugins[plugin.name] = plugin
        INFO(f"加载插件: {plugin}")

        return plugin

    def _find_plugin_class(self, module) -> Optional[Type[PluginBase]]:
        """在模块中查找 PluginBase 子类

        Args:
            module: Python 模块

        Returns:
            PluginBase 子类
        """
        for name in dir(module):
            obj = getattr(module, name)
            if (
                isinstance(obj, type) and
                issubclass(obj, PluginBase) and
                obj is not PluginBase
            ):
                return obj
        return None

    def load_builtin_plugins(self) -> None:
        """加载内置插件"""
        # 加载 Element Plus 插件
        builtin_path = Path(__file__).parent / "element_plus_plugin"
        if builtin_path.exists():
            self.load_from_path(str(builtin_path))

    def discover_plugins(self) -> List[PluginBase]:
        """从所有插件路径发现并加载插件

        Returns:
            List[PluginBase]: 加载的插件列表
        """
        plugins = []

        for plugin_path in self._plugin_paths:
            for item in plugin_path.iterdir():
                if item.is_dir() and not item.name.startswith('_'):
                    plugin = self._load_from_directory(item)
                    if plugin:
                        plugins.append(plugin)
                elif item.is_file() and item.suffix == '.py' and not item.name.startswith('_'):
                    plugin = self._load_from_file(item)
                    if plugin:
                        plugins.append(plugin)

        return plugins

    def get_plugin(self, name: str) -> Optional[PluginBase]:
        """获取插件

        Args:
            name: 插件名称

        Returns:
            PluginBase: 插件实例
        """
        return self._plugins.get(name)

    @property
    def plugins(self) -> Dict[str, PluginBase]:
        """获取所有加载的插件"""
        return self._plugins.copy()

    def get_all_keywords(self) -> Dict[str, callable]:
        """获取所有插件的关键字

        Returns:
            Dict[str, Callable]: 关键字字典
        """
        keywords = {}
        for plugin in self._plugins.values():
            keywords.update(plugin.keywords)
        return keywords

    def get_all_element_data(self) -> Dict[str, any]:
        """获取所有插件的元素数据

        Returns:
            Dict[str, Any]: 元素数据字典
        """
        element_data = {}
        for plugin in self._plugins.values():
            element_data.update(plugin.element_data)
        return element_data

    def set_page(self, page: Page) -> None:
        """设置 Page 实例

        Args:
            page: Playwright Page 实例
        """
        self._page = page
        for plugin in self._plugins.values():
            plugin.set_page(page)

    def unload_all(self) -> None:
        """卸载所有插件"""
        for plugin in self._plugins.values():
            plugin.teardown()
        self._plugins.clear()
        INFO("已卸载所有插件")
