"""插件管理器

管理本地插件的生命周期：保存、加载、验证
"""

import logging
import os
import shutil
import sys
from dataclasses import dataclass
from pathlib import Path
from typing import List, Optional

from .base import BaseTool
from .validator import ToolCodeValidator, ToolValidationResult

logger = logging.getLogger("agent")


@dataclass
class PluginInfo:
    """插件信息"""
    name: str
    path: Path
    description: str = ""
    category: str = "general"
    version: str = "0.1.0"
    enabled: bool = True


class PluginManager:
    """管理本地插件的生命周期

    插件目录结构:
    ~/.jude_agent/plugins/{plugin_name}/
        ├── __init__.py      # 包含 Tool 类
        └── metadata.json    # 插件元信息（可选）
    """

    PLUGIN_DIR_NAME = "plugins"

    def __init__(self, plugin_dir: Optional[Path] = None):
        """初始化插件管理器

        Args:
            plugin_dir: 插件目录，默认 ~/.jude_agent/plugins/
        """
        self.plugin_dir = plugin_dir or self._get_plugin_dir()
        self._ensure_plugin_dir()

    def _get_plugin_dir(self) -> Path:
        """获取插件目录"""
        home = Path.home()
        if sys.platform == "win32":
            base = Path(os.environ.get("APPDATA", home / "AppData" / "Roaming"))
        else:
            base = home / ".local" / "share" if sys.platform == "darwin" else home / ".local"

        return base / "jude_agent" / self.PLUGIN_DIR_NAME

    def _ensure_plugin_dir(self):
        """确保插件目录存在"""
        if not self.plugin_dir.exists():
            self.plugin_dir.mkdir(parents=True, exist_ok=True)
            logger.info(f"[PluginManager] 创建插件目录: {self.plugin_dir}")

    @property
    def plugin_root(self) -> Path:
        """获取插件根目录"""
        return self.plugin_dir

    def save_plugin(
        self,
        name: str,
        code: str,
        description: str = "",
        category: str = "general"
    ) -> Path:
        """保存插件到本地

        Args:
            name: 插件名称
            code: Python 代码
            description: 插件描述
            category: 插件分类

        Returns:
            Path: 插件目录路径
        """
        # 创建插件目录
        plugin_path = self.plugin_dir / name
        if plugin_path.exists():
            logger.warning(f"[PluginManager] 插件已存在，将被覆盖: {name}")
            # 备份旧版本
            backup_path = self.plugin_dir / f"{name}.backup"
            if backup_path.exists():
                shutil.rmtree(backup_path)
            shutil.move(str(plugin_path), str(backup_path))

        plugin_path.mkdir(parents=True, exist_ok=True)

        # 保存代码文件
        init_file = plugin_path / "__init__.py"
        init_file.write_text(code, encoding="utf-8")

        # 保存元信息
        metadata = {
            "name": name,
            "description": description,
            "category": category,
            "version": "0.1.0",
        }
        import json
        metadata_file = plugin_path / "metadata.json"
        metadata_file.write_text(json.dumps(metadata, ensure_ascii=False, indent=2), encoding="utf-8")

        logger.info(f"[PluginManager] 保存插件: {name} -> {plugin_path}")
        return plugin_path

    def load_plugin(self, name: str) -> Optional[BaseTool]:
        """加载插件

        Args:
            name: 插件名称

        Returns:
            Optional[BaseTool]: 工具实例
        """
        plugin_path = self.plugin_dir / name

        if not plugin_path.exists():
            logger.warning(f"[PluginManager] 插件不存在: {name}")
            return None

        # 检查 __init__.py
        init_file = plugin_path / "__init__.py"
        if not init_file.exists():
            logger.warning(f"[PluginManager] 插件缺少 __init__.py: {name}")
            return None

        try:
            # 添加到 sys.path
            plugin_path_str = str(plugin_path)
            if plugin_path_str not in sys.path:
                sys.path.insert(0, plugin_path_str)

            # 导入模块
            import importlib.util
            spec = importlib.util.spec_from_file_location(name, init_file)
            if spec and spec.loader:
                module = importlib.util.module_from_spec(spec)
                sys.modules[name] = module
                spec.loader.exec_module(module)

                # 查找 Tool 类
                for attr_name in dir(module):
                    attr = getattr(module, attr_name)
                    if (isinstance(attr, type) and
                        issubclass(attr, BaseTool) and
                        attr is not BaseTool):
                        logger.info(f"[PluginManager] 加载插件工具: {name}")
                        return attr()

            logger.warning(f"[PluginManager] 未在插件中找到 Tool 类: {name}")
            return None

        except Exception as e:
            logger.error(f"[PluginManager] 加载插件失败: {name}, 错误: {e}")
            return None

    def validate_plugin(self, name: str) -> ToolValidationResult:
        """验证插件

        Args:
            name: 插件名称

        Returns:
            ToolValidationResult: 验证结果
        """
        plugin_path = self.plugin_dir / name

        if not plugin_path.exists():
            return ToolValidationResult.failure([f"插件目录不存在: {name}"])

        init_file = plugin_path / "__init__.py"
        if not init_file.exists():
            return ToolValidationResult.failure([f"插件缺少 __init__.py: {name}"])

        # 读取代码
        code = init_file.read_text(encoding="utf-8")

        # 验证代码
        validator = ToolCodeValidator()
        return validator.validate_full(code, name)

    def list_plugins(self) -> List[PluginInfo]:
        """列出所有已安装的插件

        Returns:
            List[PluginInfo]: 插件信息列表
        """
        plugins = []

        if not self.plugin_dir.exists():
            return plugins

        for item in self.plugin_dir.iterdir():
            if not item.is_dir() or item.name.startswith('_') or item.name.startswith('.'):
                continue

            # 检查是否是有效插件
            init_file = item / "__init__.py"
            if not init_file.exists():
                continue

            # 读取元信息
            metadata_file = item / "metadata.json"
            metadata = {"name": item.name, "description": "", "category": "general", "version": "0.1.0"}

            if metadata_file.exists():
                try:
                    import json
                    metadata = json.loads(metadata_file.read_text(encoding="utf-8"))
                except Exception:
                    pass

            plugins.append(PluginInfo(
                name=item.name,
                path=item,
                description=metadata.get("description", ""),
                category=metadata.get("category", "general"),
                version=metadata.get("version", "0.1.0"),
            ))

        return plugins

    def delete_plugin(self, name: str) -> bool:
        """删除插件

        Args:
            name: 插件名称

        Returns:
            bool: 是否成功删除
        """
        plugin_path = self.plugin_dir / name

        if not plugin_path.exists():
            logger.warning(f"[PluginManager] 插件不存在，无法删除: {name}")
            return False

        try:
            shutil.rmtree(plugin_path)
            logger.info(f"[PluginManager] 删除插件: {name}")
            return True
        except Exception as e:
            logger.error(f"[PluginManager] 删除插件失败: {name}, 错误: {e}")
            return False

    def enable_plugin(self, name: str) -> bool:
        """启用插件（添加到配置）

        Args:
            name: 插件名称

        Returns:
            bool: 是否成功
        """
        # TODO: 实现插件启用功能（添加到 tools.yaml）
        logger.info(f"[PluginManager] 启用插件: {name}")
        return True

    def disable_plugin(self, name: str) -> bool:
        """禁用插件（从配置中移除）

        Args:
            name: 插件名称

        Returns:
            bool: 是否成功
        """
        # TODO: 实现插件禁用功能
        logger.info(f"[PluginManager] 禁用插件: {name}")
        return True


# ============================================================================
# 全局实例
# ============================================================================


_plugin_manager: Optional[PluginManager] = None


def get_plugin_manager() -> PluginManager:
    """获取全局插件管理器"""
    global _plugin_manager
    if _plugin_manager is None:
        _plugin_manager = PluginManager()
    return _plugin_manager
