"""ChatPlatform — abstract base class for all chat vendor integrations.

Each vendor (Discord, Telegram, Slack, etc.) implements this interface.
The dashboard and agent code interact only with this contract, never
with vendor-specific APIs directly.

Architecture:
    ChatPlatform (ABC)
        |
        +-- DiscordVendor   (discord.py)
        +-- TelegramVendor  (future migration)
        +-- SlackVendor     (future)
"""

from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from datetime import UTC, datetime
from enum import Enum, auto
from typing import Any


class PlatformState(Enum):
    """Lifecycle state of a chat platform connection."""

    DISCONNECTED = auto()
    CONNECTING = auto()
    CONNECTED = auto()
    ERROR = auto()


@dataclass
class ChatMessage:
    """Vendor-agnostic representation of a chat message."""

    content: str
    author: str
    channel_id: str
    platform: str
    timestamp: str = field(default_factory=lambda: datetime.now(UTC).isoformat())
    message_id: str | None = None
    thread_id: str | None = None
    attachments: list[str] = field(default_factory=list)
    metadata: dict[str, Any] = field(default_factory=dict)


@dataclass
class ChatThread:
    """Vendor-agnostic representation of a conversation thread."""

    thread_id: str
    title: str
    channel_id: str
    platform: str
    created_at: str = field(default_factory=lambda: datetime.now(UTC).isoformat())
    archived: bool = False
    message_count: int = 0
    metadata: dict[str, Any] = field(default_factory=dict)


@dataclass
class InviteInfo:
    """Parsed invite extracted from an image or text."""

    url: str
    code: str
    platform: str
    guild_name: str | None = None
    source: str = "unknown"  # "qr", "vision", "text"


@dataclass
class PlatformStatus:
    """Current status of a chat platform connection."""

    platform: str
    state: PlatformState
    token_set: bool
    guild_count: int = 0
    thread_count: int = 0
    error: str | None = None

    def to_dict(self) -> dict[str, Any]:
        return {
            "platform": self.platform,
            "state": self.state.name.lower(),
            "connected": self.state == PlatformState.CONNECTED,
            "token_set": self.token_set,
            "guild_count": self.guild_count,
            "thread_count": self.thread_count,
            "error": self.error,
        }


class ChatPlatform(ABC):
    """Abstract base class for chat platform integrations.

    Lifecycle:
        configure(token) -> start() -> [send/receive messages] -> stop()

    All vendors implement this interface. The dashboard routes and
    agent code work with ChatPlatform, never with vendor-specific APIs.
    """

    @property
    @abstractmethod
    def name(self) -> str:
        """Platform identifier (e.g., 'discord', 'telegram')."""

    @property
    @abstractmethod
    def state(self) -> PlatformState:
        """Current connection state."""

    @abstractmethod
    async def start(self, token: str | None = None) -> bool:
        """Start the platform connection. Returns True on success."""

    @abstractmethod
    async def stop(self) -> None:
        """Gracefully disconnect."""

    @abstractmethod
    async def send_message(
        self, channel_id: str, content: str, thread_id: str | None = None
    ) -> ChatMessage | None:
        """Send a message. Optionally within a thread."""

    @abstractmethod
    async def create_thread(
        self, channel_id: str, title: str, initial_message: str | None = None
    ) -> ChatThread | None:
        """Create a new thread in a channel."""

    @abstractmethod
    async def join_from_invite(self, invite_code: str) -> bool:
        """Join a server/workspace using an invite code."""

    @abstractmethod
    def status(self) -> PlatformStatus:
        """Return current platform status."""

    @abstractmethod
    def save_token(self, token: str) -> None:
        """Persist token for restarts."""

    @abstractmethod
    def load_token(self) -> str | None:
        """Load persisted token."""
