"""
Roneia Client - 依赖管理器

管理 Skill 和功能模块的 pip 依赖：
- 检测缺失依赖
- 自动安装依赖
- 安装后刷新模块
"""

import importlib
import subprocess
import sys
import logging
from typing import Dict, List

logger = logging.getLogger(__name__)

# Skill → pip 包的映射
SKILL_DEPENDENCIES: Dict[str, List[str]] = {
    "web_search": [
        "tavily-python>=0.5",
        "ddgs>=6.0",
        "requests>=2.28",
        "beautifulsoup4>=4.12",
    ],
    "screen_capture": [
        "pillow>=9.0",
        "pyautogui>=0.9",
    ],
    "local_file": [],
}

# 功能模块 → pip 包的映射
FEATURE_DEPENDENCIES: Dict[str, List[str]] = {
    "voice": [
        "sherpa-onnx>=1.10,<1.12",
        "edge-tts>=6.0",
        "webrtcvad-wheels>=2.0",
        "sounddevice>=0.4",
        "pydub>=0.25",
        "numpy>=1.24",
    ],
}

# pip 包名 → import 名映射（仅列出不一致的）
IMPORT_MAP: Dict[str, str] = {
    "beautifulsoup4": "bs4",
    "pillow": "PIL",
    "tavily-python": "tavily",
    "webrtcvad-wheels": "webrtcvad",
    "sherpa-onnx": "sherpa_onnx",
    "edge-tts": "edge_tts",
}


def _pkg_to_import_name(pkg_spec: str) -> str:
    """将 pip 包名（含版本约束）转换为 import 名"""
    # 去掉版本约束：beautifulsoup4>=4.12 → beautifulsoup4
    name = pkg_spec.split(">=")[0].split("<=")[0].split("<")[0].split(">")[0].split("==")[0].split("!=")[0].strip()
    return IMPORT_MAP.get(name, name.replace("-", "_"))


def _pkg_name(pkg_spec: str) -> str:
    """从包规格中提取纯包名"""
    return pkg_spec.split(">=")[0].split("<=")[0].split("<")[0].split(">")[0].split("==")[0].split("!=")[0].strip()


class DependencyManager:
    """依赖管理器"""

    def check_missing(self, skill_name: str) -> List[str]:
        """
        检查 Skill 缺失的依赖

        Args:
            skill_name: Skill 名称

        Returns:
            缺失的包规格列表（含版本约束）
        """
        packages = SKILL_DEPENDENCIES.get(skill_name, [])
        return self._find_missing(packages)

    def check_feature_missing(self, feature_name: str) -> List[str]:
        """
        检查功能模块缺失的依赖

        Args:
            feature_name: 功能名称（如 "voice"）

        Returns:
            缺失的包规格列表
        """
        packages = FEATURE_DEPENDENCIES.get(feature_name, [])
        return self._find_missing(packages)

    def _find_missing(self, packages: List[str]) -> List[str]:
        """检查哪些包未安装"""
        missing = []
        for pkg_spec in packages:
            import_name = _pkg_to_import_name(pkg_spec)
            try:
                importlib.import_module(import_name)
            except ImportError:
                missing.append(pkg_spec)
        return missing

    def install_packages(self, packages: List[str]) -> bool:
        """
        安装 pip 包

        Args:
            packages: 包规格列表（含版本约束）

        Returns:
            是否安装成功
        """
        if not packages:
            return True

        # 显示安装的包名
        names = [_pkg_name(p) for p in packages]
        print(f"  pip install {' '.join(names)}")

        try:
            result = subprocess.run(
                [sys.executable, "-m", "pip", "install", *packages],
                capture_output=True,
                text=True,
                timeout=300,
            )

            if result.returncode == 0:
                return True
            else:
                print(f"  [错误] pip install 失败:")
                # 只显示最后几行错误
                error_lines = result.stderr.strip().split("\n")
                for line in error_lines[-5:]:
                    print(f"    {line}")
                return False

        except subprocess.TimeoutExpired:
            print("  [错误] 安装超时（5分钟）")
            return False
        except Exception as e:
            print(f"  [错误] 安装失败: {e}")
            return False

    def reload_skill_module(self, skill_name: str) -> bool:
        """
        重载 Skill 模块以刷新 HAS_* 标志

        Args:
            skill_name: Skill 名称

        Returns:
            是否重载成功
        """
        module_name = f"roneia_core.builtin_skills.{skill_name}"
        try:
            if module_name in sys.modules:
                module = sys.modules[module_name]
                importlib.reload(module)
                logger.info(f"Reloaded module: {module_name}")
            else:
                importlib.import_module(module_name)
                logger.info(f"Imported module: {module_name}")
            return True
        except Exception as e:
            print(f"  [警告] 模块重载失败，建议重启客户端: {e}")
            logger.error(f"Failed to reload {module_name}: {e}")
            return False
