"""AlbusOS -- framework for building multi-agent systems.

Quick start::

    from albusos import agent, run

    a = agent("researcher", instructions="Research topics.", tools=["web.*"])
    result = await run(a, "What is quantum computing?")

Multi-turn::

    from albusos import agent, Session

    a = agent("researcher", instructions="Research topics.", tools=["web.*"])
    session = Session(a)
    r1 = await session.run("What is quantum computing?")
    r2 = await session.run("Tell me more about qubits")

Custom pathways (power-user)::

    from albusos import AgentBuilder, PathwayBuilder, run

    pathway = (
        PathwayBuilder("qa", pathway_id="qa")
        .llm("answer", "Answer: {{input.goal}}")
        .connect("input", "answer")
        .connect("answer", "output")
        .build()
    )
    a = AgentBuilder().id("qa").pathway("qa").build()
    result = await run(a, "What is 2+2?", pathway=pathway)
"""

from __future__ import annotations

# ---------------------------------------------------------------------------
# Agent runtime
# ---------------------------------------------------------------------------
from core.agent import Agent, AgentRepository

# ---------------------------------------------------------------------------
# Builders (primary authoring interface)
# ---------------------------------------------------------------------------
from core.builders.agent import AgentBuilder
from core.builders.pathway import PathwayBuilder
from core.builders.skill import SkillBuilder

# ---------------------------------------------------------------------------
# Tool authoring
# ---------------------------------------------------------------------------
from core.pathways.models.tool import ToolOutput
from core.pathways.nodes.handoff import HandoffCandidate

# ---------------------------------------------------------------------------
# Pathway primitives
# ---------------------------------------------------------------------------
from core.pathways.pathway import Pathway, PathwayMode

# ---------------------------------------------------------------------------
# Runner (zero-boilerplate execution)
# ---------------------------------------------------------------------------
from core.runner import Session
from core.runner import run as _core_run
from core.tools import ToolRegistry, get_tool_registry

# ---------------------------------------------------------------------------
# Core types
# ---------------------------------------------------------------------------
from core.types.agents import AgentDefinition, ModelRouting
from core.types.execution import ExecutionBudget, ExecutionResult
from core.types.state import ThreadState

# ---------------------------------------------------------------------------
# Stdlib bootstrap (opt-in, called automatically by agent() and run())
# ---------------------------------------------------------------------------
from stdlib.bootstrap import load_stdlib

# ---------------------------------------------------------------------------
# State tracking for auto-init
# ---------------------------------------------------------------------------
_stdlib_loaded = False


def _ensure_stdlib() -> None:
    """Load stdlib tools + LLM providers on first use (idempotent)."""
    global _stdlib_loaded
    if not _stdlib_loaded:
        load_stdlib()
        _stdlib_loaded = True


# ---------------------------------------------------------------------------
# agent() — the human-friendly factory
# ---------------------------------------------------------------------------


def agent(
    id: str,
    *,
    instructions: str = "",
    tools: list[str] | None = None,
    model: str = "reasoning",
    name: str | None = None,
    temperature: float = 0.7,
    max_steps: int = 10,
) -> AgentDefinition:
    """Create an agent in one call.

    This is the simplest way to define an agent.  It auto-loads the
    standard tools and LLM providers on first use, and returns an
    ``AgentDefinition`` that ``run()`` / ``Session`` know how to
    execute with the built-in tool-calling loop.

    Parameters
    ----------
    id
        Unique identifier (e.g. ``"researcher"``).
    instructions
        System prompt — tell the agent what it does.
    tools
        Tool patterns the agent can use (e.g. ``["web.*", "memory.*"]``).
        Defaults to ``["*"]`` (all tools).
    model
        Capability name (``"reasoning"``, ``"fast"``, ``"code"``) or
        explicit model string.
    name
        Human-readable display name.  Defaults to *id*.
    temperature
        Sampling temperature.
    max_steps
        Maximum tool-calling rounds per turn.

    Returns
    -------
    AgentDefinition
        Ready to pass to ``run()`` or ``Session``.
    """
    _ensure_stdlib()
    builder = AgentBuilder().id(id).instructions(instructions).model(model)
    builder = builder.temperature(temperature).max_steps(max_steps)
    if name:
        builder = builder.name(name)
    for pattern in tools or ["*"]:
        builder = builder.tool(pattern)
    return builder.build()


# ---------------------------------------------------------------------------
# run() — auto-loads stdlib before executing
# ---------------------------------------------------------------------------


async def run(
    agent_or_definition: Agent | AgentDefinition,
    message: str,
    **kwargs: object,
) -> ExecutionResult:
    """Execute a single agent turn (auto-loads stdlib on first call).

    Accepts the same keyword arguments as ``core.runner.run``:
    ``pathway``, ``thread_id``, ``budget``, ``state_store``.
    """
    _ensure_stdlib()
    return await _core_run(agent_or_definition, message, **kwargs)  # type: ignore[arg-type]


__all__ = [
    "Agent",
    "AgentBuilder",
    "AgentDefinition",
    "AgentRepository",
    "ExecutionBudget",
    "ExecutionResult",
    "HandoffCandidate",
    "ModelRouting",
    "Pathway",
    "PathwayBuilder",
    "PathwayMode",
    "Session",
    "SkillBuilder",
    "ThreadState",
    "ToolOutput",
    "ToolRegistry",
    "agent",
    "get_tool_registry",
    "load_stdlib",
    "run",
]
