"""AgentBuilder - Fluent API for constructing Agent definitions.

Accepts both string IDs and typed objects for composition:

    pathway = PathwayBuilder("dispatch").tool(...).build()
    skill = SkillBuilder().id("svc").name("SVC").build()

    agent = (
        AgentBuilder()
        .id("researcher")
        .name("Research Agent")
        .instructions("You are a research specialist.")
        .tool("web.*")
        .skill(skill)          # Skill object or string ID
        .pathway(pathway)      # Pathway object or string ID
        .model("reasoning")
        .build()
    )

When ``.pathway()`` is not called, the builder defaults to the
built-in tool-calling loop (``__default__``).  The runner auto-deploys
this pathway at execution time.
"""

import uuid
from typing import Self

from core.pathways.pathway import Pathway
from core.skills.models import Skill
from core.types import AgentDefinition
from core.types.agents import ModelRouting


class AgentBuilder:
    """Fluent builder for creating agents.

    Required fields (must be set before build()):
    - id: Unique identifier for the agent (auto-generated if not set)
    - name: Human-readable name (defaults to id if not set)
    """

    def __init__(self) -> None:
        """Initialize a new agent builder with default values."""
        self._id: str | None = None
        self._name: str | None = None
        self._instructions: str = ""
        self._tools: list[str] = []
        self._skills: list[str] = []
        self._handoff_description: str = ""
        self._max_steps: int = 10
        self._model: str = "reasoning"
        self._pathway: str | None = None
        self._temperature: float = 0.7
        self._workspace_id: str | None = None
        self._model_routing: ModelRouting | None = None

    def id(self, id: str) -> Self:
        self._id = id
        return self

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

    def instructions(self, instructions: str) -> Self:
        self._instructions = instructions
        return self

    def tool(self, tool_pattern: str) -> Self:
        self._tools.append(tool_pattern)
        return self

    def skill(self, skill_ref: str | Skill) -> Self:
        """Add a skill by ID or object.

        Args:
            skill_ref: Skill ID string or a built Skill object.
        """
        self._skills.append(skill_ref if isinstance(skill_ref, str) else skill_ref.id)
        return self

    def handoff_description(self, description: str) -> Self:
        self._handoff_description = description
        return self

    def max_steps(self, steps: int) -> Self:
        self._max_steps = steps
        return self

    def model(self, model: str) -> Self:
        self._model = model
        return self

    def pathway(self, pathway_ref: str | Pathway) -> Self:
        """Set the pathway by ID or object.

        Args:
            pathway_ref: Pathway ID string or a built Pathway object.
        """
        self._pathway = pathway_ref if isinstance(pathway_ref, str) else pathway_ref.id
        return self

    def temperature(self, temp: float) -> Self:
        self._temperature = temp
        return self

    def workspace(self, workspace_id: str) -> Self:
        self._workspace_id = workspace_id
        return self

    def model_routing(
        self,
        *,
        planning: str = "reasoning",
        execution: str = "fast",
        evaluation: str = "reasoning",
    ) -> Self:
        """Set per-phase model routing.

        Args:
            planning: Model for initial reasoning (first round)
            execution: Model for tool-calling rounds
            evaluation: Model for synthesis (final round)
        """
        self._model_routing = ModelRouting(
            planning=planning,
            execution=execution,
            evaluation=evaluation,
        )
        return self

    def build(self) -> AgentDefinition:
        if not self._id:
            self._id = f"agent_{uuid.uuid4().hex[:8]}"
        if not self._name:
            self._name = self._id
        if not self._pathway:
            self._pathway = "__default__"

        # Only pass tools if the caller explicitly added them; otherwise
        # let AgentDefinition's Pydantic default apply.
        kwargs: dict = {
            "id": self._id,
            "name": self._name,
            "instructions": self._instructions,
            "skills": self._skills,
            "handoff_description": self._handoff_description,
            "max_steps": self._max_steps,
            "model": self._model,
            "pathway": self._pathway,
            "temperature": self._temperature,
            "workspace_id": self._workspace_id,
            "model_routing": self._model_routing,
        }
        if self._tools:
            kwargs["tools"] = self._tools
        return AgentDefinition(**kwargs)


def agent_builder() -> Self:
    """Create a new agent builder."""
    return AgentBuilder()


__all__ = [
    "AgentBuilder",
    "agent_builder",
]
