#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Skill管理器
负责加载、管理和执行Skills
"""

import os
import sys
import importlib.util
import inspect
from typing import Dict, List, Optional, Any, Tuple
from pathlib import Path


class SkillManager:
    """Skill管理器"""
    
    def __init__(self, toolkit_instance=None):
        """
        初始化Skill管理器
        
        Args:
            toolkit_instance: NetworkToolkit实例
        """
        self.toolkit = toolkit_instance
        self.skills: Dict[str, Any] = {}  # skill_name -> skill_instance
        self.categories: Dict[str, List[str]] = {}  # category -> [skill_names]
        self.loaded_files: List[str] = []  # 已加载的文件路径
    
    def load_skills(self, skills_dir: str = "./skills"):
        """
        从目录加载所有Skills
        
        Args:
            skills_dir: Skills目录路径
        """
        skills_path = Path(skills_dir)
        if not skills_path.exists():
            print(f"⚠️ Skills目录不存在: {skills_dir}")
            return
        
        # 递归遍历所有子目录
        for root, dirs, files in os.walk(skills_dir):
            for file in files:
                if file.endswith("_skill.py") and not file.startswith("__"):
                    filepath = os.path.join(root, file)
                    self._load_skill_from_file(filepath)
        
        print(f"✅ 共加载{len(self.skills)}个Skills,分布在{len(self.categories)}个分类中")
    
    def _load_skill_from_file(self, filepath: str):
        """
        从文件加载单个Skill
        
        Args:
            filepath: Skill文件路径
        """
        try:
            # 动态导入模块
            module_name = Path(filepath).stem
            spec = importlib.util.spec_from_file_location(module_name, filepath)
            if spec is None or spec.loader is None:
                print(f"❌ 无法加载模块: {filepath}")
                return
            
            module = importlib.util.module_from_spec(spec)
            sys.modules[module_name] = module
            spec.loader.exec_module(module)
            
            # 导入BaseSkill(避免循环导入)
            from .base_skill import BaseSkill
            
            # 查找BaseSkill子类
            skill_classes = []
            for name, obj in inspect.getmembers(module, inspect.isclass):
                if issubclass(obj, BaseSkill) and obj != BaseSkill:
                    skill_classes.append(obj)
            
            if not skill_classes:
                print(f"⚠️ 未找到Skill类: {filepath}")
                return
            
            # 实例化Skill
            for skill_class in skill_classes:
                try:
                    skill_instance = skill_class(self.toolkit)
                    metadata = skill_instance.get_metadata()
                    skill_name = metadata["name"]
                    
                    # 检查重复
                    if skill_name in self.skills:
                        print(f"⚠️ Skill名称重复: {skill_name}, 跳过{filepath}")
                        continue
                    
                    # 注册Skill
                    self.skills[skill_name] = skill_instance
                    self.loaded_files.append(filepath)
                    
                    # 分类管理
                    category = metadata.get("category", "other")
                    if category not in self.categories:
                        self.categories[category] = []
                    self.categories[category].append(skill_name)
                    
                    print(f"  ✅ {metadata['display_name']} ({skill_name})")
                    
                except Exception as e:
                    print(f"  ❌ 实例化Skill失败 {skill_class.__name__}: {e}")
        
        except Exception as e:
            print(f"❌ 加载Skill文件失败 {filepath}: {e}")
            import traceback
            traceback.print_exc()
    
    def get_skill(self, skill_name: str) -> Optional[Any]:
        """
        获取指定Skill
        
        Args:
            skill_name: Skill名称
            
        Returns:
            Skill实例或None
        """
        return self.skills.get(skill_name)
    
    def find_skill_by_query(self, query: str) -> Optional[Tuple[Any, float]]:
        """
        根据查询找到最匹配的Skill
        
        Args:
            query: 用户查询字符串
            
        Returns:
            (Skill实例, 匹配度) 或 None
        """
        best_skill = None
        best_score = 0.0
        
        for skill in self.skills.values():
            score = skill.match_query(query)
            if score > best_score:
                best_score = score
                best_skill = skill
        
        # 只返回匹配度>0.3的结果
        if best_score > 0.3:
            return best_skill, best_score
        return None
    
    def get_all_skills_metadata(self) -> List[Dict[str, Any]]:
        """获取所有Skills的元数据"""
        return [skill.get_metadata() for skill in self.skills.values()]
    
    def get_skills_by_category(self, category: str) -> List[Any]:
        """
        获取指定分类的所有Skills
        
        Args:
            category: 分类名称
            
        Returns:
            Skill实例列表
        """
        skill_names = self.categories.get(category, [])
        return [self.skills[name] for name in skill_names if name in self.skills]
    
    def execute_skill(self, skill_name: str, params: Dict[str, Any]) -> str:
        """
        执行指定Skill
        
        Args:
            skill_name: Skill名称
            params: 参数字典
            
        Returns:
            执行结果字符串
        """
        skill = self.get_skill(skill_name)
        if not skill:
            return f"❌ 未找到Skill: {skill_name}"
        
        # 验证参数
        valid, error_msg = skill.validate_params(params)
        if not valid:
            return f"❌ 参数验证失败: {error_msg}"
        
        # 执行Skill（过滤掉内部传递的下划线参数，如 _raw_query）
        try:
            exec_params = {k: v for k, v in params.items() if not k.startswith('_')}
            return skill.execute(**exec_params)
        except Exception as e:
            import traceback
            error_detail = traceback.format_exc()
            return f"❌ Skill执行失败: {str(e)}\n\n详细错误:\n{error_detail}"
    
    def generate_ai_prompt(self) -> str:
        """
        生成AI工具路由器的提示词
        
        Returns:
            系统提示词字符串
        """
        prompt_parts = [
            "你是AI工具路由器,负责将用户请求转换为可执行的Skill调用。",
            "",
            "【输出格式】",
            "只输出JSON对象,不要有任何额外文本、注释或Markdown代码块:",
            '{"skill":"skill_name","params":{...}}',
            '或 {"skill":"none","answer":"原因"}',
            "",
            "【可用Skills】"
        ]
        
        # 分类名称映射
        category_names = {
            "network": "🌐 网络诊断",
            "system": "⚙️ 系统操作",
            "info": "📊 信息查询",
            "advanced": "🔧 高级功能",
            "other": "🔹 其他"
        }
        
        # 按分类组织Skills
        for category in ["network", "system", "info", "advanced", "other"]:
            if category not in self.categories:
                continue
            
            skill_names = self.categories[category]
            if not skill_names:
                continue
            
            category_display = category_names.get(category, category)
            prompt_parts.append(f"\n## {category_display}")
            
            for skill_name in skill_names:
                skill = self.skills.get(skill_name)
                if not skill:
                    continue
                
                metadata = skill.get_metadata()
                
                prompt_parts.append(f"\n### {metadata['display_name']} ({skill_name})")
                prompt_parts.append(f"描述: {metadata['description']}")
                
                # 参数说明
                parameters = metadata.get("parameters", [])
                if parameters:
                    prompt_parts.append("参数:")
                    for param in parameters:
                        required = "必需" if param.get("required") else "可选"
                        default = f",默认={param['default']}" if "default" in param else ""
                        prompt_parts.append(
                            f"  - {param['name']} ({param['type']},{required}{default}): {param['description']}"
                        )
                
                # 示例
                examples = metadata.get("examples", [])
                if examples:
                    prompt_parts.append("示例: " + ", ".join(f'"{ex}"' for ex in examples[:3]))
                
                # 特殊要求
                if metadata.get("requires_admin"):
                    prompt_parts.append("⚠️ 需要管理员权限")
                if metadata.get("requires_ui"):
                    prompt_parts.append("⚠️ 需要UI交互")
        
        # 添加规则
        prompt_parts.extend([
            "",
            "【路由规则】",
            "1. 缺少必需参数时返回none并说明缺失信息",
            "2. 参数类型要正确:字符串用引号,数字和布尔值不用引号",
            "3. 优先使用专用Skill而非通用命令",
            "4. 危险操作要在answer中明确警告",
            "5. 无法确定目标时返回none并要求用户提供更多信息",
            "6. 参数值要规范化(如DNS记录类型用大写:A/AAAA/CNAME等)",
            ""
        ])
        
        return "\n".join(prompt_parts)
    
    def get_statistics(self) -> Dict[str, Any]:
        """
        获取统计信息
        
        Returns:
            统计信息字典
        """
        return {
            "total_skills": len(self.skills),
            "categories": len(self.categories),
            "loaded_files": len(self.loaded_files),
            "skills_by_category": {
                category: len(skill_names)
                for category, skill_names in self.categories.items()
            }
        }
    
    def reload_skill(self, skill_name: str) -> bool:
        """
        重新加载指定Skill(用于开发调试)
        
        Args:
            skill_name: Skill名称
            
        Returns:
            是否成功
        """
        if skill_name not in self.skills:
            return False
        
        # 找到对应的文件
        skill_instance = self.skills[skill_name]
        filepath = None
        for loaded_file in self.loaded_files:
            if skill_name in loaded_file:
                filepath = loaded_file
                break
        
        if not filepath:
            return False
        
        # 移除旧的
        metadata = skill_instance.get_metadata()
        category = metadata.get("category", "other")
        if category in self.categories and skill_name in self.categories[category]:
            self.categories[category].remove(skill_name)
        del self.skills[skill_name]
        self.loaded_files.remove(filepath)
        
        # 重新加载
        self._load_skill_from_file(filepath)
        return skill_name in self.skills
    
    def __str__(self):
        """字符串表示"""
        stats = self.get_statistics()
        return f"SkillManager({stats['total_skills']} skills in {stats['categories']} categories)"
    
    def __repr__(self):
        """开发者表示"""
        return f"<SkillManager: {len(self.skills)} skills>"
