"""Skill tools - Allow agents to invoke pathways as skills.

This bridges the Agent abstraction to Pack pathways:
- skill.invoke: Run a pathway as a discrete skill
- skill.list: List available skills from loaded packs

Skills are pathways that an agent can call as tools during AgentLoop execution.
"""

from __future__ import annotations

import logging
from typing import Any, TYPE_CHECKING

from stdlib.registry import register_tool

if TYPE_CHECKING:
    from pathway_engine.domain.context import Context

logger = logging.getLogger(__name__)


# =============================================================================
# SKILL REGISTRY (runtime populated by Agent)
# =============================================================================

# agent_id -> skill_id -> pathway_builder
_SKILL_REGISTRY: dict[str, dict[str, Any]] = {}


def register_skill(
    agent_id: str,
    skill_id: str,
    pathway_builder: Any,
    description: str = "",
) -> None:
    """Register a pathway as a skill for an agent."""
    if agent_id not in _SKILL_REGISTRY:
        _SKILL_REGISTRY[agent_id] = {}
    _SKILL_REGISTRY[agent_id][skill_id] = {
        "builder": pathway_builder,
        "description": description,
    }
    logger.debug(f"Registered skill {skill_id} for agent {agent_id}")


def get_skill(agent_id: str, skill_id: str) -> Any | None:
    """Get a skill's pathway builder."""
    return _SKILL_REGISTRY.get(agent_id, {}).get(skill_id, {}).get("builder")


def list_skills(agent_id: str) -> list[dict[str, str]]:
    """List all skills for an agent."""
    skills = _SKILL_REGISTRY.get(agent_id, {})
    return [
        {"id": skill_id, "description": info.get("description", "")}
        for skill_id, info in skills.items()
    ]


def clear_skills(agent_id: str | None = None) -> None:
    """Clear skill registry (optionally for specific agent)."""
    if agent_id:
        _SKILL_REGISTRY.pop(agent_id, None)
    else:
        _SKILL_REGISTRY.clear()


# =============================================================================
# TOOLS
# =============================================================================


@register_tool(
    "skill.invoke",
    description="Invoke a pathway as a skill. Skills are discrete capabilities from loaded packs.",
    parameters={
        "type": "object",
        "properties": {
            "skill_id": {
                "type": "string",
                "description": "The skill/pathway ID to invoke (e.g., 'my_agent.main.v1')",
            },
            "inputs": {
                "type": "object",
                "description": "Inputs to pass to the skill/pathway",
            },
            "agent_id": {
                "type": "string",
                "description": "Agent ID (for skill lookup)",
                "default": "default",
            },
        },
        "required": ["skill_id", "inputs"],
    },
)
async def skill_invoke(inputs: dict[str, Any], context: Any = None) -> dict[str, Any]:
    """Invoke a pathway as a skill.

    This allows AgentLoopNode to call pack pathways as tools.
    """
    from pathway_engine.application.kernel.vm import PathwayVM

    skill_id = inputs.get("skill_id", "")
    skill_inputs = inputs.get("inputs", {})
    agent_id = inputs.get("agent_id", "default")

    # Get the pathway builder
    skill_info = _SKILL_REGISTRY.get(agent_id, {}).get(skill_id)
    if not skill_info:
        # Try without agent scoping (global skills)
        skill_info = _SKILL_REGISTRY.get("global", {}).get(skill_id)

    if not skill_info:
        logger.warning(f"Skill not found: {skill_id} for agent {agent_id}")
        return {
            "success": False,
            "error": f"Skill not found: {skill_id}",
            "available_skills": list_skills(agent_id),
        }

    builder = skill_info.get("builder")
    if not builder:
        return {"success": False, "error": f"Skill has no builder: {skill_id}"}

    try:
        # Build the pathway
        pathway = builder()

        # Execute (but validate first so errors are actionable)
        vm = PathwayVM()
        try:
            from pathway_engine.application.validation import validate_pathway

            validation = validate_pathway(pathway, vm.ctx)
            if not validation.valid:
                return {
                    "success": False,
                    "skill_id": skill_id,
                    "error": "skill_pathway_invalid",
                    "validation": validation.to_dict(),
                }
        except Exception:
            # Best-effort: validation should never block execution if it fails unexpectedly.
            pass

        result = await vm.execute(pathway, skill_inputs, context)

        if result:
            return {
                "success": True,
                "skill_id": skill_id,
                "outputs": result.outputs,
                "status": (
                    result.status.value
                    if hasattr(result.status, "value")
                    else str(result.status)
                ),
            }
        else:
            return {
                "success": False,
                "skill_id": skill_id,
                "error": "Pathway execution returned no result",
            }

    except Exception as e:
        logger.error(f"Skill invocation failed: {skill_id}", exc_info=True)
        return {
            "success": False,
            "skill_id": skill_id,
            "error": str(e),
        }


@register_tool(
    "skill.list",
    description="List available skills for an agent.",
    parameters={
        "type": "object",
        "properties": {
            "agent_id": {
                "type": "string",
                "description": "Agent ID",
                "default": "default",
            },
        },
    },
)
async def skill_list(inputs: dict[str, Any], context: Any = None) -> dict[str, Any]:
    """List available skills."""
    agent_id = inputs.get("agent_id", "default")
    skills = list_skills(agent_id)

    # Also include global skills
    global_skills = list_skills("global")
    all_skills = skills + [s for s in global_skills if s not in skills]

    return {
        "agent_id": agent_id,
        "skills": all_skills,
        "count": len(all_skills),
    }


__all__ = [
    "skill_invoke",
    "skill_list",
    "register_skill",
    "get_skill",
    "list_skills",
    "clear_skills",
]
