"""Skill - A discrete capability an agent can use.

Skills are the bridge between Agents and Pathways:
- Agents have skills (what they CAN do)
- Skills wrap pathways (HOW they do it)
- Bundles group related skills (optional organization)

This replaces the awkward Pack → Pathway relationship with a cleaner:
    Agent → Skills → Pathways (internal)
"""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, Callable, TYPE_CHECKING

if TYPE_CHECKING:
    from pathway_engine.domain.pathway import Pathway
    from pathway_engine.domain.context import Context


@dataclass
class Skill:
    """A discrete capability an agent can invoke.

    Skills are the "verbs" of an agent - things it can DO.
    Each skill wraps a pathway that implements the capability.

    Example:
        triage_skill = Skill(
            id="triage_maintenance",
            name="Maintenance Triage",
            description="Classify urgency and route to appropriate vendor",
            pathway_builder=build_triage_pathway,
            inputs_schema={
                "request": "string - the maintenance request text",
                "unit": "string - the unit number",
                "tenant_name": "string - tenant's name",
            },
            outputs_schema={
                "urgency": "emergency|high|medium|low",
                "category": "plumbing|electrical|hvac|...",
                "response": "string - message to send to tenant",
            },
        )
    """

    id: str
    name: str
    description: str = ""

    # The pathway that implements this skill
    pathway_builder: Callable[[], "Pathway"] | None = None
    
    # For API-created skills: reference to stored pathway
    pathway_id: str | None = None

    # Schema documentation (for agent/LLM understanding)
    inputs_schema: dict[str, str] = field(default_factory=dict)
    outputs_schema: dict[str, str] = field(default_factory=dict)

    # Optional: trigger configuration (when to auto-invoke)
    triggers: list["SkillTrigger"] = field(default_factory=list)

    # Tags for categorization
    tags: list[str] = field(default_factory=list)

    async def invoke(
        self,
        inputs: dict[str, Any],
        ctx: "Context",
    ) -> dict[str, Any]:
        """Execute this skill with given inputs."""
        from pathway_engine.application.kernel.vm import PathwayVM

        if not self.pathway_builder:
            return {"error": f"Skill {self.id} has no pathway"}

        pathway = self.pathway_builder()
        vm = PathwayVM()
        result = await vm.execute(pathway, inputs, ctx)

        if result:
            return {"success": True, "outputs": result.outputs}
        return {"success": False, "error": "Pathway execution failed"}

    def to_tool_schema(self) -> dict[str, Any]:
        """Generate tool schema for LLM function calling."""
        properties = {}
        required = []

        for key, desc in self.inputs_schema.items():
            # Parse simple type hints from description
            if " - " in desc:
                type_hint, description = desc.split(" - ", 1)
            else:
                type_hint, description = "string", desc

            properties[key] = {
                "type": (
                    type_hint
                    if type_hint in ["string", "number", "boolean", "object", "array"]
                    else "string"
                ),
                "description": description,
            }
            required.append(key)

        return {
            "name": f"skill_{self.id}",
            "description": self.description,
            "parameters": {
                "type": "object",
                "properties": properties,
                "required": required,
            },
        }

    def to_dict(self) -> dict[str, Any]:
        result = {
            "id": self.id,
            "name": self.name,
            "description": self.description,
            "inputs_schema": self.inputs_schema,
            "outputs_schema": self.outputs_schema,
            "tags": self.tags,
        }
        if self.pathway_id:
            result["pathway_id"] = self.pathway_id
        return result


@dataclass
class SkillTrigger:
    """When to auto-invoke a skill.

    Similar to Pack triggers but attached to individual skills.
    """

    source: str  # "webhook", "timer", "event"
    filter: dict[str, Any] = field(
        default_factory=dict
    )  # e.g., {"topic": "maintenance"}
    schedule: str | None = None  # Cron for timer triggers
    inputs_map: dict[str, str] = field(default_factory=dict)  # event → skill inputs


@dataclass
class SkillBundle:
    """A collection of related skills.

    Bundles are optional organization - agents can use skills directly
    or import entire bundles.

    Example:
        support_bundle = SkillBundle(
            id="customer_support",
            name="Customer Support Skills",
            skills=[triage_skill, faq_skill, escalation_skill],
        )

        agent = agent_builder().use_bundle(property_bundle).build()
    """

    id: str
    name: str
    description: str = ""
    skills: list[Skill] = field(default_factory=list)
    version: str = "1.0.0"
    author: str | None = None
    tags: list[str] = field(default_factory=list)

    def get_skill(self, skill_id: str) -> Skill | None:
        """Get a skill by ID."""
        for skill in self.skills:
            if skill.id == skill_id:
                return skill
        return None

    def list_skills(self) -> list[str]:
        """List all skill IDs in this bundle."""
        return [s.id for s in self.skills]

    def to_dict(self) -> dict[str, Any]:
        return {
            "id": self.id,
            "name": self.name,
            "description": self.description,
            "version": self.version,
            "skills": [s.to_dict() for s in self.skills],
            "tags": self.tags,
        }


class SkillBuilder:
    """Fluent builder for skills."""

    def __init__(self):
        self._id: str = "skill"
        self._name: str = "Skill"
        self._description: str = ""
        self._pathway_builder: Callable[[], "Pathway"] | None = None
        self._inputs: dict[str, str] = {}
        self._outputs: dict[str, str] = {}
        self._triggers: list[SkillTrigger] = []
        self._tags: list[str] = []

    def id(self, skill_id: str) -> "SkillBuilder":
        self._id = skill_id
        return self

    def name(self, name: str) -> "SkillBuilder":
        self._name = name
        return self

    def description(self, desc: str) -> "SkillBuilder":
        self._description = desc
        return self

    def pathway(self, builder: Callable[[], "Pathway"]) -> "SkillBuilder":
        self._pathway_builder = builder
        return self

    def input(self, name: str, description: str) -> "SkillBuilder":
        self._inputs[name] = description
        return self

    def output(self, name: str, description: str) -> "SkillBuilder":
        self._outputs[name] = description
        return self

    def on_webhook(
        self, topic: str, inputs_map: dict[str, str] | None = None
    ) -> "SkillBuilder":
        self._triggers.append(
            SkillTrigger(
                source="webhook",
                filter={"topic": topic},
                inputs_map=inputs_map or {},
            )
        )
        return self

    def on_schedule(
        self, cron: str, inputs_map: dict[str, str] | None = None
    ) -> "SkillBuilder":
        self._triggers.append(
            SkillTrigger(
                source="timer",
                schedule=cron,
                inputs_map=inputs_map or {},
            )
        )
        return self

    def tag(self, *tags: str) -> "SkillBuilder":
        self._tags.extend(tags)
        return self

    def build(self) -> Skill:
        return Skill(
            id=self._id,
            name=self._name,
            description=self._description,
            pathway_builder=self._pathway_builder,
            inputs_schema=self._inputs,
            outputs_schema=self._outputs,
            triggers=self._triggers,
            tags=self._tags,
        )


def skill_builder() -> SkillBuilder:
    """Create a fluent skill builder."""
    return SkillBuilder()


class BundleBuilder:
    """Fluent builder for skill bundles."""

    def __init__(self):
        self._id: str = "bundle"
        self._name: str = "Bundle"
        self._description: str = ""
        self._skills: list[Skill] = []
        self._version: str = "1.0.0"
        self._author: str | None = None
        self._tags: list[str] = []

    def id(self, bundle_id: str) -> "BundleBuilder":
        self._id = bundle_id
        return self

    def name(self, name: str) -> "BundleBuilder":
        self._name = name
        return self

    def description(self, desc: str) -> "BundleBuilder":
        self._description = desc
        return self

    def skill(self, skill: Skill) -> "BundleBuilder":
        self._skills.append(skill)
        return self

    def version(self, version: str) -> "BundleBuilder":
        self._version = version
        return self

    def author(self, author: str) -> "BundleBuilder":
        self._author = author
        return self

    def tag(self, *tags: str) -> "BundleBuilder":
        self._tags.extend(tags)
        return self

    def build(self) -> SkillBundle:
        return SkillBundle(
            id=self._id,
            name=self._name,
            description=self._description,
            skills=self._skills,
            version=self._version,
            author=self._author,
            tags=self._tags,
        )


def bundle_builder() -> BundleBuilder:
    """Create a fluent bundle builder."""
    return BundleBuilder()


__all__ = [
    "Skill",
    "SkillTrigger",
    "SkillBundle",
    "SkillBuilder",
    "BundleBuilder",
    "skill_builder",
    "bundle_builder",
]
