"""Topology validation for multi-agent teams."""
from __future__ import annotations

from logos_adk.errors import RoutingError


def resolve_topology(
    topology: str | dict[str, list[str]] | None,
    agent_names: list[str],
) -> dict[str, set[str]]:
    """Resolve a topology spec into an adjacency map.

    Args:
        topology: "mesh", a dict of allowed targets, or None (defaults to mesh).
        agent_names: List of agent names in the team.

    Returns:
        Dict mapping each agent name to the set of agents it can send to.
    """
    if topology is None or topology == "mesh":
        name_set = set(agent_names)
        return {name: name_set - {name} for name in agent_names}

    if isinstance(topology, dict):
        all_names = set(agent_names)
        result: dict[str, set[str]] = {}
        for source, targets in topology.items():
            if source not in all_names:
                raise ValueError(
                    f"Agent '{source}' in topology is not in agent list: {agent_names}"
                )
            for target in targets:
                if target not in all_names:
                    raise ValueError(
                        f"Target '{target}' in topology for '{source}' "
                        f"is not in agent list: {agent_names}"
                    )
            result[source] = set(targets)
        # Agents not mentioned in topology cannot send to anyone
        for name in agent_names:
            if name not in result:
                result[name] = set()
        return result

    raise ValueError(f"Invalid topology: {topology!r}. Use 'mesh' or a dict.")


def validate_send(
    from_agent: str,
    to_agent: str,
    topology: dict[str, set[str]],
) -> None:
    """Validate that from_agent is allowed to send to to_agent.

    Raises:
        RoutingError: If the send is not allowed.
    """
    if from_agent == to_agent:
        raise RoutingError(f"Agent '{from_agent}' cannot send to itself")

    if to_agent not in topology:
        raise RoutingError(f"Agent '{to_agent}' not found in team topology")

    allowed = topology.get(from_agent, set())
    if to_agent not in allowed:
        raise RoutingError(
            f"Send from '{from_agent}' to '{to_agent}' is not allowed by topology. "
            f"Allowed targets: {sorted(allowed)}"
        )
