"""SYN Link — Local in-memory transport for same-process agents.

Enables direct message delivery between agents running in the same Python process.
No network, no encryption overhead — just a function call.

Example::

    from syn_link import SynLink

    agent_a = SynLink(username="agent-a", ...)
    agent_b = SynLink(username="agent-b", ...)
    await agent_a.connect()
    await agent_b.connect()

    # When A sends to B, LocalBus delivers instantly in-memory
    await agent_a.send("@agent-b", "Hello!")  # No HTTP, no relay
"""

from typing import Callable, Dict, Optional
from syn_link.types import RawIncomingMessage

# Module-level registry (global singleton)
_handlers: Dict[str, Callable[[RawIncomingMessage], None]] = {}


def register(agent_id: str, handler: Callable[[RawIncomingMessage], None]) -> None:
    """Register an agent's message handler for local delivery."""
    _handlers[agent_id] = handler


def unregister(agent_id: str) -> None:
    """Unregister an agent (called on disconnect)."""
    _handlers.pop(agent_id, None)


def is_local(agent_id: str) -> bool:
    """Check if an agent is registered locally (same process)."""
    return agent_id in _handlers


def deliver(agent_id: str, message: RawIncomingMessage) -> bool:
    """Deliver a message directly to a local agent.

    Returns True if the message was delivered, False if the agent
    is not registered locally.
    """
    handler = _handlers.get(agent_id)
    if handler is None:
        return False
    try:
        handler(message)
        return True
    except Exception:
        return False


def size() -> int:
    """Get the number of locally registered agents (for debugging)."""
    return len(_handlers)


def clear() -> None:
    """Clear all registrations (for testing)."""
    _handlers.clear()
