from __future__ import annotations

from dataclasses import dataclass, field
from datetime import datetime


def _parse_dt(v: str | datetime | None) -> datetime | None:
    """Parse an ISO 8601 / RFC3339 datetime string, or pass through datetime/None."""
    if v is None:
        return None
    if isinstance(v, datetime):
        return v
    # Handle Z suffix
    if v.endswith("Z"):
        v = v[:-1] + "+00:00"
    return datetime.fromisoformat(v)


@dataclass
class AgentInfo:
    public_key: str
    display_name: str | None
    status: str
    metadata: dict[str, str]
    capabilities: list[str]
    created_at: datetime
    last_active_at: datetime

    @classmethod
    def from_dict(cls, d: dict) -> AgentInfo:
        return cls(
            public_key=d["public_key"],
            display_name=d.get("display_name"),
            status=d["status"],
            metadata=d.get("metadata") or {},
            capabilities=d.get("capabilities") or [],
            created_at=_parse_dt(d["created_at"]),
            last_active_at=_parse_dt(d["last_active_at"]),
        )


@dataclass
class Attachment:
    blob_id: str
    content_type: str | None = None
    size: int | None = None
    hash: str | None = None

    def to_dict(self) -> dict:
        d: dict = {"blob_id": self.blob_id}
        if self.content_type is not None:
            d["content_type"] = self.content_type
        if self.size is not None:
            d["size"] = self.size
        if self.hash is not None:
            d["hash"] = self.hash
        return d

    @classmethod
    def from_dict(cls, d: dict) -> Attachment:
        return cls(
            blob_id=d["blob_id"],
            content_type=d.get("content_type"),
            size=d.get("size"),
            hash=d.get("hash"),
        )


@dataclass
class Message:
    message_id: str
    sender_key: str
    recipient_key: str
    content_type: str
    body: dict | None
    attachments: list[Attachment]
    status: str
    thread_id: str | None
    in_reply_to: str | None
    metadata: dict[str, str]
    created_at: datetime
    expires_at: datetime
    delivered_at: datetime | None = None

    @classmethod
    def from_dict(cls, d: dict) -> Message:
        return cls(
            message_id=d["message_id"],
            sender_key=d["sender_key"],
            recipient_key=d["recipient_key"],
            content_type=d.get("content_type", "application/json"),
            body=d.get("body"),
            attachments=[Attachment.from_dict(a) for a in (d.get("attachments") or [])],
            status=d["status"],
            thread_id=d.get("thread_id"),
            in_reply_to=d.get("in_reply_to"),
            metadata=d.get("metadata") or {},
            created_at=_parse_dt(d["created_at"]),
            expires_at=_parse_dt(d["expires_at"]),
            delivered_at=_parse_dt(d.get("delivered_at")),
        )


@dataclass
class SendResult:
    message_id: str
    status: str
    created_at: datetime
    expires_at: datetime

    @classmethod
    def from_dict(cls, d: dict) -> SendResult:
        return cls(
            message_id=d["message_id"],
            status=d["status"],
            created_at=_parse_dt(d["created_at"]),
            expires_at=_parse_dt(d["expires_at"]),
        )


@dataclass
class MessageStatus:
    status: str
    created_at: datetime
    delivered_at: datetime | None
    expires_at: datetime

    @classmethod
    def from_dict(cls, d: dict) -> MessageStatus:
        return cls(
            status=d["status"],
            created_at=_parse_dt(d["created_at"]),
            delivered_at=_parse_dt(d.get("delivered_at")),
            expires_at=_parse_dt(d["expires_at"]),
        )


@dataclass
class PollResult:
    messages: list[Message]
    next_cursor: str | None = None

    @classmethod
    def from_dict(cls, d: dict) -> PollResult:
        return cls(
            messages=[Message.from_dict(m) for m in (d.get("messages") or [])],
            next_cursor=d.get("next_cursor"),
        )


@dataclass
class DiscoveredAgent:
    public_key: str
    display_name: str | None
    last_active_at: datetime
    capabilities: list[str]

    @classmethod
    def from_dict(cls, d: dict) -> DiscoveredAgent:
        return cls(
            public_key=d["public_key"],
            display_name=d.get("display_name"),
            last_active_at=_parse_dt(d["last_active_at"]),
            capabilities=d.get("capabilities") or [],
        )


@dataclass
class DiscoverResult:
    agents: list[DiscoveredAgent]
    next_cursor: str | None = None
    has_more: bool = False

    @classmethod
    def from_dict(cls, d: dict) -> DiscoverResult:
        return cls(
            agents=[DiscoveredAgent.from_dict(a) for a in (d.get("agents") or [])],
            next_cursor=d.get("next_cursor"),
            has_more=d.get("has_more", False),
        )


@dataclass
class CapabilityInfo:
    tag: str
    agent_count: int

    @classmethod
    def from_dict(cls, d: dict) -> CapabilityInfo:
        return cls(tag=d["tag"], agent_count=d["agent_count"])


@dataclass
class CapabilitiesResult:
    capabilities: list[CapabilityInfo]

    @classmethod
    def from_dict(cls, d: dict) -> CapabilitiesResult:
        return cls(
            capabilities=[CapabilityInfo.from_dict(c) for c in (d.get("capabilities") or [])],
        )


@dataclass
class Blob:
    blob_id: str
    hash: str
    size: int
    content_type: str
    created_at: datetime
    expires_at: datetime

    @classmethod
    def from_dict(cls, d: dict) -> Blob:
        return cls(
            blob_id=d["blob_id"],
            hash=d["hash"],
            size=d["size"],
            content_type=d["content_type"],
            created_at=_parse_dt(d["created_at"]),
            expires_at=_parse_dt(d["expires_at"]),
        )


@dataclass
class BlobMetadata:
    content_type: str
    size: int
    hash: str


@dataclass
class WebhookInfo:
    webhook_id: str
    url: str
    events: list[str]
    created_at: datetime

    @classmethod
    def from_dict(cls, d: dict) -> WebhookInfo:
        return cls(
            webhook_id=d["webhook_id"],
            url=d["url"],
            events=d.get("events") or [],
            created_at=_parse_dt(d["created_at"]),
        )
