"""CollaborationMixin — team communication, A2A messaging, events."""
from __future__ import annotations
from typing import Any
from datetime import datetime

from logos_adk.a2a import A2ARequest, A2AResponse
from logos_adk.event_bus import EventRecord


class CollaborationMixin:
    async def send_to(self, to_agent: str, message: Any) -> None:
        """Send a message to another agent in the same team.

        Raises:
            RuntimeError: If the agent is not part of a team.
            RoutingError: If topology disallows the send.
        """
        if self._team is None:
            raise RuntimeError(f"Agent '{self.name}' is not part of a team")
        await self._team.send(self.name, to_agent, message)

    async def broadcast_msg(self, message: Any) -> None:
        """Broadcast a message to all allowed agents in the team.

        Raises:
            RuntimeError: If the agent is not part of a team.
        """
        if self._team is None:
            raise RuntimeError(f"Agent '{self.name}' is not part of a team")
        await self._team.broadcast(self.name, message)

    def publish_event(
        self,
        topic: str,
        payload: dict[str, Any],
        *,
        campaign_id: str | None = None,
        correlation_id: str | None = None,
        run_id: str | None = None,
        dedupe_key: str | None = None,
        available_in_seconds: float = 0.0,
    ) -> EventRecord:
        """Publish an event into the shared team event bus."""
        if self._team is None:
            raise RuntimeError(f"Agent '{self.name}' is not part of a team")
        return self._team.publish_event(
            self.name,
            topic,
            payload,
            campaign_id=campaign_id,
            correlation_id=correlation_id,
            run_id=run_id,
            dedupe_key=dedupe_key,
            available_in_seconds=available_in_seconds,
        )

    def schedule_event(
        self,
        topic: str,
        payload: dict[str, Any],
        *,
        delay_seconds: float | None = None,
        due_at: datetime | None = None,
        campaign_id: str | None = None,
        correlation_id: str | None = None,
        run_id: str | None = None,
        dedupe_key: str | None = None,
    ) -> EventRecord:
        """Schedule a future event on the shared team event bus."""
        if self._team is None:
            raise RuntimeError(f"Agent '{self.name}' is not part of a team")
        return self._team.schedule_event(
            self.name,
            topic,
            payload,
            delay_seconds=delay_seconds,
            due_at=due_at,
            campaign_id=campaign_id,
            correlation_id=correlation_id,
            run_id=run_id,
            dedupe_key=dedupe_key,
        )

    def schedule_task(
        self,
        task: str,
        *,
        to_agent: str | None = None,
        delay_seconds: float | None = None,
        due_at: datetime | None = None,
        session_id: str | None = None,
        campaign_id: str | None = None,
        correlation_id: str | None = None,
        run_id: str | None = None,
        dedupe_key: str | None = None,
        metadata: dict[str, Any] | None = None,
    ) -> EventRecord:
        """Schedule a future task for this agent or another team member."""
        if self._team is None:
            raise RuntimeError(f"Agent '{self.name}' is not part of a team")
        return self._team.schedule_task(
            self.name,
            task,
            to_agent=to_agent,
            delay_seconds=delay_seconds,
            due_at=due_at,
            session_id=session_id,
            campaign_id=campaign_id,
            correlation_id=correlation_id,
            run_id=run_id,
            dedupe_key=dedupe_key,
            metadata=metadata,
        )

    def subscribe_topic(
        self,
        topic: str,
        *,
        handler: Any | None = None,
        publish_to: str | None = None,
        name: str | None = None,
    ) -> CollaborationMixin:
        """Subscribe this agent to a topic on the shared team event bus."""
        subscription = {
            "topic": topic,
            "handler": handler,
            "publish_to": publish_to,
            "name": name,
        }
        if self._team is None:
            self._pending_topic_subscriptions.append(subscription)
            return self
        self._team.subscribe(
            self.name,
            topic,
            handler=handler,
            publish_to=publish_to,
            name=name,
        )
        return self

    async def send_a2a(
        self,
        to_agent: str,
        task: str,
        *,
        metadata: dict[str, Any] | None = None,
        expects_response: bool = False,
        conversation_id: str | None = None,
    ) -> str:
        if self._team is None:
            raise RuntimeError(f"Agent '{self.name}' is not part of a team")
        request = A2ARequest(
            from_agent=self.name,
            to_agent=to_agent,
            content=task,
            conversation_id=conversation_id,
            metadata=metadata or {},
            expects_response=expects_response,
        )
        await self._team.send(self.name, to_agent, request)
        return request.task_id

    async def request_a2a(
        self,
        to_agent: str,
        task: str,
        *,
        metadata: dict[str, Any] | None = None,
        conversation_id: str | None = None,
    ) -> A2AResponse:
        if self._team is None:
            raise RuntimeError(f"Agent '{self.name}' is not part of a team")
        return await self._team.request_a2a(
            self.name,
            to_agent,
            task,
            metadata=metadata,
            conversation_id=conversation_id,
        )

    async def respond_a2a(
        self,
        request: A2ARequest,
        content: str,
        *,
        status: str = "completed",
        error: str | None = None,
        metadata: dict[str, Any] | None = None,
    ) -> None:
        if self._team is None:
            raise RuntimeError(f"Agent '{self.name}' is not part of a team")
        response = A2AResponse(
            from_agent=self.name,
            to_agent=request.from_agent,
            content=content,
            conversation_id=request.conversation_id,
            metadata=metadata or {},
            request_id=request.task_id,
            status=status,
            error=error,
        )
        await self._team.send(self.name, request.from_agent, response)
