"""SkillRegistry - Skill 注册中心（v2: 版本管理、能力查询、依赖检查）"""

from __future__ import annotations

import logging
from typing import TYPE_CHECKING

from agentkit.core.exceptions import SkillNotFoundError
from agentkit.skills.base import Skill, SkillConfig
from agentkit.skills.schema import DependencyDecl, HealthCheckResult

if TYPE_CHECKING:
    from agentkit.skills.pipeline import SkillPipeline

logger = logging.getLogger(__name__)


class SkillRegistry:
    """Skill 注册中心，管理 Skill 的注册、发现、更新

    v2 增强：
    - 版本管理：同名 Skill 可注册多个版本，默认使用最新版
    - 能力查询：按 capability 标签查询匹配的 Skill
    - 依赖检查：health_check() 验证所有声明依赖是否已注册
    """

    def __init__(self):
        self._skills: dict[str, Skill] = {}
        # 版本历史：name → {version → Skill}
        self._skill_versions: dict[str, dict[str, Skill]] = {}
        self._pipelines: dict[str, SkillPipeline] = {}

    def register(self, skill: Skill) -> None:
        """注册 Skill，支持多版本共存

        同名 Skill 注册时保留版本历史，默认指向最新注册的版本。
        """
        name = skill.name
        version = skill.version

        # 维护版本历史
        if name not in self._skill_versions:
            self._skill_versions[name] = {}
        self._skill_versions[name][version] = skill

        # 默认指向最新注册的版本
        self._skills[name] = skill
        logger.info(f"Skill '{name}' v{version} registered")

    def unregister(self, name: str, version: str | None = None) -> None:
        """注销 Skill

        Args:
            name: Skill 名称
            version: 可选版本号。若指定则仅注销该版本；
                     若不指定则注销所有版本。
        """
        if version is not None:
            # 仅注销指定版本
            if name in self._skill_versions and version in self._skill_versions[name]:
                del self._skill_versions[name][version]
                logger.info(f"Skill '{name}' v{version} unregistered")
                # 如果删除的是当前默认版本，切换到最新版本
                if name in self._skills and self._skills[name].version == version:
                    remaining = self._skill_versions[name]
                    if remaining:
                        latest = max(remaining.keys())
                        self._skills[name] = remaining[latest]
                        logger.info(
                            f"Skill '{name}' default switched to v{latest}"
                        )
                    else:
                        del self._skills[name]
                        del self._skill_versions[name]
        else:
            # 注销所有版本
            if name in self._skills:
                del self._skills[name]
            if name in self._skill_versions:
                del self._skill_versions[name]
            logger.info(f"Skill '{name}' unregistered (all versions)")

    def get(self, name: str, version: str | None = None) -> Skill:
        """获取 Skill

        Args:
            name: Skill 名称
            version: 可选版本号。若指定则返回特定版本，否则返回默认（最新）版本。

        Raises:
            SkillNotFoundError: Skill 或指定版本不存在
        """
        if version is not None:
            if name not in self._skill_versions:
                raise SkillNotFoundError(name)
            if version not in self._skill_versions[name]:
                raise SkillNotFoundError(f"{name}@{version}")
            return self._skill_versions[name][version]

        if name not in self._skills:
            raise SkillNotFoundError(name)
        return self._skills[name]

    def list_skills(self) -> list[Skill]:
        """列出所有已注册的 Skill（每个名称返回默认版本）"""
        return list(self._skills.values())

    def update_skill(self, name: str, config: SkillConfig) -> Skill:
        """更新已注册 Skill 的配置，返回更新后的 Skill"""
        if name not in self._skills:
            raise SkillNotFoundError(name)
        old_skill = self._skills[name]
        new_skill = Skill(config, tools=old_skill.tools)
        self._skills[name] = new_skill
        # 同时更新版本历史
        version = config.version
        if name not in self._skill_versions:
            self._skill_versions[name] = {}
        self._skill_versions[name][version] = new_skill
        logger.info(f"Skill '{name}' updated to v{version}")
        return new_skill

    def has_skill(self, name: str, version: str | None = None) -> bool:
        """检查 Skill 是否已注册

        Args:
            name: Skill 名称
            version: 可选版本号
        """
        if version is not None:
            return (
                name in self._skill_versions
                and version in self._skill_versions[name]
            )
        return name in self._skills

    # ---- 版本管理 ----

    def get_versions(self, name: str) -> list[str]:
        """获取指定 Skill 的所有已注册版本号

        Args:
            name: Skill 名称

        Returns:
            版本号列表（按注册顺序）

        Raises:
            SkillNotFoundError: Skill 不存在
        """
        if name not in self._skill_versions:
            raise SkillNotFoundError(name)
        return list(self._skill_versions[name].keys())

    # ---- 能力查询 ----

    def query_by_capability(self, tag: str) -> list[Skill]:
        """按能力标签查询 Skill

        Args:
            tag: 能力标签名（如 "rag", "terminal", "computer_use"）

        Returns:
            匹配的 Skill 列表
        """
        result = []
        for skill in self._skills.values():
            capability_tags = [
                cap.tag for cap in skill.capabilities
            ]
            if tag in capability_tags:
                result.append(skill)
        return result

    # ---- 依赖检查 ----

    def health_check(self, name: str | None = None) -> list[HealthCheckResult]:
        """依赖健康检查

        验证所有声明依赖是否已注册，以及版本约束是否满足。

        Args:
            name: 可选，指定检查某个 Skill。若不指定则检查所有 Skill。

        Returns:
            健康检查结果列表
        """
        if name is not None:
            if name not in self._skills:
                raise SkillNotFoundError(name)
            skills_to_check = [self._skills[name]]
        else:
            skills_to_check = list(self._skills.values())

        results = []
        for skill in skills_to_check:
            result = self._check_skill_dependencies(skill)
            results.append(result)

        return results

    def _check_skill_dependencies(self, skill: Skill) -> HealthCheckResult:
        """检查单个 Skill 的依赖是否满足"""
        result = HealthCheckResult(
            skill_name=skill.name,
            skill_version=skill.version,
            healthy=True,
        )

        for dep in skill.dependencies:
            if dep.type == "skill":
                if not self.has_skill(dep.name):
                    if dep.required:
                        result.healthy = False
                        result.missing_dependencies.append(dep.name)
                    else:
                        result.warnings.append(
                            f"Optional skill dependency '{dep.name}' not registered"
                        )
                elif dep.version_constraint:
                    # 简化版本约束检查：仅检查已注册版本是否满足
                    dep_skill = self.get(dep.name)
                    if not self._check_version_constraint(
                        dep_skill.version, dep.version_constraint
                    ):
                        result.version_mismatches.append(
                            f"{dep.name}: need {dep.version_constraint}, "
                            f"got {dep_skill.version}"
                        )
                        if dep.required:
                            result.healthy = False
            elif dep.type == "tool":
                # Tool 依赖检查需要 ToolRegistry，此处仅记录
                # 实际检查在运行时由 SkillLoader 配合 ToolRegistry 完成
                pass

        return result

    @staticmethod
    def _check_version_constraint(
        actual_version: str, constraint: str
    ) -> bool:
        """简化的版本约束检查

        支持基本的约束格式：
        - ">=x.y.z" — 大于等于
        - "<=x.y.z" — 小于等于
        - "==x.y.z" — 精确匹配
        - ">=x.y.z,<a.b.c" — 范围约束

        使用简单的元组比较进行 semver 检查。
        """
        try:
            actual = tuple(int(x) for x in actual_version.split("."))
        except (ValueError, AttributeError):
            return True  # 无法解析时默认通过

        parts = [p.strip() for p in constraint.split(",")]
        for part in parts:
            if part.startswith(">="):
                target = tuple(int(x) for x in part[2:].split("."))
                if actual < target:
                    return False
            elif part.startswith("<="):
                target = tuple(int(x) for x in part[2:].split("."))
                if actual > target:
                    return False
            elif part.startswith("=="):
                target = tuple(int(x) for x in part[2:].split("."))
                if actual != target:
                    return False
            elif part.startswith(">"):
                target = tuple(int(x) for x in part[1:].split("."))
                if actual <= target:
                    return False
            elif part.startswith("<"):
                target = tuple(int(x) for x in part[1:].split("."))
                if actual >= target:
                    return False
        return True

    # ---- Pipeline 管理 ----

    def register_pipeline(self, pipeline: SkillPipeline) -> None:
        """注册 SkillPipeline，同名覆盖"""
        self._pipelines[pipeline.name] = pipeline
        logger.info(f"SkillPipeline '{pipeline.name}' registered")

    def get_pipeline(self, name: str) -> SkillPipeline | None:
        """获取已注册的 SkillPipeline，不存在返回 None"""
        return self._pipelines.get(name)

    def list_pipelines(self) -> list[str]:
        """列出所有已注册的 Pipeline 名称"""
        return list(self._pipelines.keys())

    def unregister_pipeline(self, name: str) -> None:
        """注销 SkillPipeline"""
        if name in self._pipelines:
            del self._pipelines[name]
            logger.info(f"SkillPipeline '{name}' unregistered")
