"""
Data types for the Dexgram bot SDK.

These mirror the SimpleX Chat API types used in commands and events.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from enum import Enum
from typing import Any


class ChatType(str, Enum):
    DIRECT = "@"
    GROUP = "#"
    LOCAL = "*"


class ChatPeerType(str, Enum):
    HUMAN = "human"
    BOT = "bot"


class CIDeleteMode(str, Enum):
    BROADCAST = "broadcast"
    INTERNAL = "internal"


class GroupMemberRole(str, Enum):
    OBSERVER = "observer"
    MEMBER = "member"
    ADMIN = "admin"
    OWNER = "owner"


@dataclass
class Profile:
    display_name: str
    full_name: str = ""
    image: str | None = None
    peer_type: ChatPeerType | None = None
    preferences: dict[str, Any] | None = None

    def to_dict(self) -> dict[str, Any]:
        d: dict[str, Any] = {
            "displayName": self.display_name,
            "fullName": self.full_name,
        }
        if self.image is not None:
            d["image"] = self.image
        if self.peer_type is not None:
            d["peerType"] = self.peer_type.value
        if self.preferences is not None:
            d["preferences"] = self.preferences
        return d

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> Profile:
        return cls(
            display_name=data.get("displayName", ""),
            full_name=data.get("fullName", ""),
            image=data.get("image"),
            peer_type=ChatPeerType(data["peerType"]) if data.get("peerType") else None,
            preferences=data.get("preferences"),
        )


@dataclass
class Contact:
    contact_id: int
    local_display_name: str
    profile: Profile
    active_conn: bool = True
    raw: dict[str, Any] = field(default_factory=dict)

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> Contact:
        profile_data = data.get("profile") or data.get("localProfile", {})
        return cls(
            contact_id=data.get("contactId", 0),
            local_display_name=data.get("localDisplayName", ""),
            profile=Profile.from_dict(profile_data),
            active_conn=data.get("activeConn", True),
            raw=data,
        )

    @property
    def id(self) -> int:
        return self.contact_id

    @property
    def name(self) -> str:
        return self.local_display_name or self.profile.display_name

    @property
    def is_bot(self) -> bool:
        return self.profile.peer_type == ChatPeerType.BOT


@dataclass
class User:
    user_id: int
    local_display_name: str
    profile: Profile
    raw: dict[str, Any] = field(default_factory=dict)

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> User:
        profile_data = data.get("profile", data.get("localProfile", {}))
        return cls(
            user_id=data.get("userId", 0),
            local_display_name=data.get("localDisplayName", ""),
            profile=Profile.from_dict(profile_data),
            raw=data,
        )

    @property
    def id(self) -> int:
        return self.user_id


@dataclass
class ChatItem:
    chat_item_id: int
    content: dict[str, Any]
    meta: dict[str, Any]
    raw: dict[str, Any] = field(default_factory=dict)

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> ChatItem:
        return cls(
            chat_item_id=data.get("meta", {}).get("itemId", 0),
            content=data.get("content", {}),
            meta=data.get("meta", {}),
            raw=data,
        )

    @property
    def id(self) -> int:
        return self.chat_item_id

    @property
    def text(self) -> str:
        return self.meta.get("itemText", "")

    @property
    def msg_content(self) -> dict[str, Any] | None:
        return self.content.get("msgContent")


@dataclass
class GroupInfo:
    group_id: int
    local_display_name: str
    group_profile: dict[str, Any]
    raw: dict[str, Any] = field(default_factory=dict)

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> GroupInfo:
        return cls(
            group_id=data.get("groupId", 0),
            local_display_name=data.get("localDisplayName", ""),
            group_profile=data.get("groupProfile", {}),
            raw=data,
        )

    @property
    def id(self) -> int:
        return self.group_id


@dataclass
class GroupMember:
    group_member_id: int
    member_role: str
    raw: dict[str, Any] = field(default_factory=dict)

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> GroupMember:
        return cls(
            group_member_id=data.get("groupMemberId", 0),
            member_role=data.get("memberRole", "member"),
            raw=data,
        )


@dataclass
class MsgContent:
    """Represents a message content payload for sending."""
    type: str
    text: str
    extra: dict[str, Any] = field(default_factory=dict)

    def to_dict(self) -> dict[str, Any]:
        d: dict[str, Any] = {"type": self.type, "text": self.text}
        d.update(self.extra)
        return d

    @classmethod
    def text_content(cls, text: str) -> MsgContent:
        return cls(type="text", text=text)

    @classmethod
    def link_content(cls, text: str, preview: dict[str, Any]) -> MsgContent:
        return cls(type="link", text=text, extra={"preview": preview})

    @classmethod
    def file_content(cls, text: str = "") -> MsgContent:
        return cls(type="file", text=text)


@dataclass
class ComposedMessage:
    msg_content: MsgContent
    file_source: dict[str, Any] | None = None
    quoted_item_id: int | None = None
    mentions: dict[str, int] = field(default_factory=dict)

    def to_dict(self) -> dict[str, Any]:
        return {
            "fileSource": self.file_source,
            "quotedItemId": self.quoted_item_id,
            "msgContent": self.msg_content.to_dict(),
            "mentions": self.mentions,
        }
