from dateutil import parser
from typing import Optional, List, TYPE_CHECKING

from ..util import prettify, get_optional, get_optional_list
from ..enums import ChatChannelType, ChatMessageType
from .current_user_attributes import ChatChannelUserAttributes
from .user import UserCompact


if TYPE_CHECKING:
    from datetime import datetime


class ChatChannel:
    """
    Represents an individual chat "channel" in the game.

    **Attributes**

    channel_id: :class:`int`

    name: :class:`str`

    description: Optional[:class:`str`]

    icon: Optional[:class:`str`]
        display icon for the channel

    type: :class:`ChatChannelType`
        Below are the channel types and their permission checks for joining/messaging:
        PUBLIC
            None
        PRIVATE
            is player in the allowed groups? (channel.allowed_groups)
        MULTIPLAYER
            is player currently in the mp game?
        SPECTATOR
            None
        TEMPORARY
            deprecated
        PM
            For PMs, two factors are taken into account:
            Is either user blocking the other? If so, deny.
            Does the target only accept PMs from friends? Is the current user a friend? If not, deny.
        GROUP
            is player in channel? (user_channels)
        ANNOUNCE
            is user in the announce group?

    moderated: :class:`bool`
        user can't send message when the value is `True`

    uuid: Optional[:class:`str`]
        value from requests that is relayed back to the sender.

    current_user_attributes: Optional[:class:`ChatChannelUserAttributes`]
        only present on some responses

    last_message_id: Optional[:class:`int`]
        message_id of last known message (only returned in presence responses)

    recent_messages: Optional[List[:class:`ChatMessage`]]
        [DEPRECATED] up to 50 most recent messages

    users: Optional[List[:class:`int`]]
        list of user ids that are in the channel (not included for PUBLIC channels).
    """

    __slots__ = (
        "channel_id",
        "name",
        "description",
        "icon",
        "type",
        "moderated",
        "uuid",
        "current_user_attributes",
        "last_message_id",
        "recent_messages",
        "users",
    )

    def __init__(self, data):
        self.channel_id: int = data["channel_id"]
        self.name: str = data["name"]
        self.description: Optional[str] = data.get("description")
        self.icon: Optional[str] = data.get("icon")
        self.type: ChatChannelType = ChatChannelType(data["type"])
        self.moderated: bool = data["moderated"]

        self.uuid: Optional[str] = data.get("uuid")
        self.current_user_attributes: Optional[ChatChannelUserAttributes] = get_optional(
            data, "current_user_attributes", ChatChannelUserAttributes
        )
        self.last_message_id: Optional[int] = data.get("last_message_id")
        self.recent_messages: Optional[List[ChatMessage]] = get_optional_list(data, "recent_messages", ChatMessage)
        self.users: Optional[List[int]] = data.get("users")

    def __repr__(self):
        return prettify(self, "name")


class ChatMessage:
    """
    Represents an individual Message within a :class:`ChatChannel`.

    **Attributes**

    channel_id: :class:`int`
        channel_id of where the message was sent

    content: :class:`str`
        message content

    is_action: :class:`bool`
        was this an action? i.e. /me dances

    message_id: :class:`int`
        unique identifier for message

    sender_id: :class:`int`
        user_id of the sender

    timestamp: :class:`datetime.datetime`
        when the message was sent

    type: :class:`ChatMessageType`

    uuid: Optional[:class:`str`]
        message identifier originally sent by client

    sender: Optional[:class:`UserCompact`]
        embedded :class:`UserCompact` object to save additional api lookups
    """

    __slots__ = (
        "channel_id",
        "content",
        "is_action",
        "message_id",
        "sender_id",
        "timestamp",
        "type",
        "uuid",
        "sender",
    )

    def __init__(self, data):
        self.channel_id: int = data["channel_id"]
        self.content: str = data["content"]
        self.is_action: bool = data["is_action"]
        self.message_id: int = data["message_id"]
        self.sender_id: int = data["sender_id"]
        self.timestamp: datetime = parser.parse(data["timestamp"])
        self.type: ChatMessageType = ChatMessageType(data["type"])
        self.uuid: Optional[str] = data.get("uuid")
        self.sender: Optional[UserCompact] = get_optional(data, "sender", UserCompact)

    def __repr__(self):
        return prettify(self, "sender_id" if self.sender is None else "sender", "content")
