from abc import ABC, abstractmethod
from typing import AsyncIterator, Dict, Any

from gateway.protocol import UserMessage, AgentMessage, ChannelStatus


class Channel(ABC):
    """Abstract base class for communication channels.

    Channels are the transport layer between users and the agent system.
    They handle protocol-specific encoding/decoding and maintain connection state.
    """

    def __init__(self, channel_id: str, channel_type: str):
        self.channel_id = channel_id
        self.channel_type = channel_type
        self._connected = False

    @abstractmethod
    async def send(self, message: AgentMessage) -> None:
        """Send a message from the agent to the user through this channel.

        Args:
            message: AgentMessage to send (may be streaming chunk or complete message)
        """
        pass

    @abstractmethod
    async def receive(self) -> AsyncIterator[UserMessage]:
        """Receive messages from the user through this channel.

        Yields:
            UserMessage objects as they arrive
        """
        pass

    @abstractmethod
    async def close(self) -> None:
        """Close the channel and clean up resources."""
        pass

    def supports_streaming(self) -> bool:
        """Whether this channel supports streaming responses.

        Returns:
            True if the channel can handle streaming chunks
        """
        return False

    def supports_attachments(self) -> bool:
        """Whether this channel supports file attachments.

        Returns:
            True if the channel can handle attachments
        """
        return False

    def get_status(self) -> ChannelStatus:
        """Get current channel status.

        Returns:
            ChannelStatus object with connection info and capabilities
        """
        return ChannelStatus(
            channel_id=self.channel_id,
            channel_type=self.channel_type,
            connected=self._connected,
            capabilities={
                "streaming": self.supports_streaming(),
                "attachments": self.supports_attachments(),
                "markdown": True  # Most channels support some form of markdown
            }
        )
