"""Inter-agent message format and routing.

Provides a lightweight Pydantic model for messages exchanged between
LangGraph agent nodes, plus a helper to append messages to graph state.
"""

from __future__ import annotations

import uuid
from datetime import datetime
from typing import Any, Dict, List, Optional

from pydantic import BaseModel, Field


class AgentMessage(BaseModel):
    """Message exchanged between LangGraph agent nodes."""

    id: str = Field(default_factory=lambda: uuid.uuid4().hex[:12])
    sender: str = ""
    recipient: str = ""            # empty = broadcast
    content: str = ""
    message_type: str = "request"  # request | response | error | human_gate
    metadata: Dict[str, Any] = Field(default_factory=dict)
    timestamp: str = Field(default_factory=lambda: datetime.utcnow().isoformat() + "Z")

    def to_state_dict(self) -> Dict[str, Any]:
        """Convert to plain dict suitable for WorkflowState.messages."""
        return self.model_dump()


def route_message(
    state: Dict[str, Any],
    message: AgentMessage,
) -> Dict[str, Any]:
    """Append a message to the state's message list and return updated state.

    This is a pure function — it returns a *new* dict with the message
    appended (LangGraph reducers expect this pattern).
    """
    messages: List[Dict[str, Any]] = list(state.get("messages", []))
    messages.append(message.to_state_dict())
    return {**state, "messages": messages}


def create_request(
    sender: str,
    recipient: str,
    content: str,
    **metadata: Any,
) -> AgentMessage:
    """Convenience factory for a request message."""
    return AgentMessage(
        sender=sender,
        recipient=recipient,
        content=content,
        message_type="request",
        metadata=metadata,
    )


def create_response(
    sender: str,
    recipient: str,
    content: str,
    **metadata: Any,
) -> AgentMessage:
    """Convenience factory for a response message."""
    return AgentMessage(
        sender=sender,
        recipient=recipient,
        content=content,
        message_type="response",
        metadata=metadata,
    )


def create_error(
    sender: str,
    content: str,
    **metadata: Any,
) -> AgentMessage:
    """Convenience factory for an error message."""
    return AgentMessage(
        sender=sender,
        content=content,
        message_type="error",
        metadata=metadata,
    )


def create_human_gate(
    sender: str,
    content: str,
    phase: str = "",
    **metadata: Any,
) -> AgentMessage:
    """Convenience factory for a human-in-the-loop gate message."""
    return AgentMessage(
        sender=sender,
        content=content,
        message_type="human_gate",
        metadata={"phase": phase, **metadata},
    )


def filter_messages(
    messages: List[Dict[str, Any]],
    sender: Optional[str] = None,
    recipient: Optional[str] = None,
    message_type: Optional[str] = None,
    limit: int = 50,
) -> List[Dict[str, Any]]:
    """Filter messages by sender, recipient, and/or type."""
    results = []
    for msg in messages:
        if sender and msg.get("sender") != sender:
            continue
        if recipient and msg.get("recipient") != recipient:
            continue
        if message_type and msg.get("message_type") != message_type:
            continue
        results.append(msg)
        if len(results) >= limit:
            break
    return results
