"""Contains packets related to the chat."""

from __future__ import annotations

from typing import List, Optional, Tuple
from uuid import UUID

from pymine_net.types.buffer import Buffer
from pymine_net.types.chat import Chat
from pymine_net.types.packet import ClientBoundPacket, ServerBoundPacket

__all__ = (
    "PlayChatMessageClientBound",
    "PlayChatMessageServerBound",
    "PlayTabCompleteClientBound",
    "PlayTabCompleteServerBound",
)


class PlayChatMessageClientBound(ClientBoundPacket):
    """A chat message from the server to the client (Server -> Client)

    :param Chat data: The actual chat data.
    :param int position: Where on the GUI the message is to be displayed.
    :param UUID sender: Used by the Notchian client for the disableChat launch option. Setting both longs to 0 will always display the message regardless of the setting.
    :ivar int id: Unique packet ID.
    :ivar data:
    :ivar position:
    :ivar sender:
    """

    id = 0x0F

    def __init__(self, data: Chat, position: int, sender: UUID):
        super().__init__()

        self.data = data
        self.position = position
        self.sender = sender

    def pack(self) -> Buffer:
        return Buffer().write_chat(self.data).write("b", self.position).write_uuid(self.sender)


class PlayChatMessageServerBound(ServerBoundPacket):
    """A chat message from a client to the server. Can be a command. (Client -> Server)

    :param str message: The raw text sent by the client.
    :ivar int id: Unique packet ID.
    :ivar message:
    """

    id = 0x03

    def __init__(self, message: str):
        super().__init__()

        self.message = message

    @classmethod
    def unpack(cls, buf: Buffer) -> PlayChatMessageServerBound:
        return cls(buf.read_string())


class PlayTabCompleteServerBound(ServerBoundPacket):
    """Used when a client wants to tab complete a chat message. (Client -> Server)

    :param int transaction_id: Number generated by the client.
    :param str text: All text behind / to the left of the cursor.
    :ivar int id: Unique packet ID.
    :ivar transaction_id:
    :ivar text:
    """

    id = 0x06

    def __init__(self, transaction_id: int, text: str):
        super().__init__()

        self.transaction_id = transaction_id
        self.text = text

    @classmethod
    def unpack(cls, buf: Buffer) -> PlayTabCompleteServerBound:
        return cls(buf.read_varint(), buf.read_string())


class PlayTabCompleteClientBound(ClientBoundPacket):
    """Sends a list of auto-completions for a command. For regular chat, this would be a player username. Command names and parameters are also supported. (Server -> Client)

    :param int transaction_id: Number generated by the client.
    :param int start: Start of the text to replace.
    :param int length: Length of the text to replace.
    :param list matches: List of matches.
    :ivar int id: Unique packet ID.
    :ivar transaction_id:
    :ivar start:
    :ivar matches:
    """

    id = 0x11

    def __init__(self, transaction_id: int, start: int, matches: List[Tuple[str, Optional[Chat]]]):
        super().__init__()

        self.transaction_id = transaction_id
        self.start = start
        self.matches = matches

    def pack(self) -> Buffer:
        buf = (
            Buffer()
            .write_varint(self.id)
            .write_varint(self.start)
            .write_varint(self.length)
            .write_varint(len(self.matches))
        )

        for match, tooltip in self.matches:
            buf.write_string(match)

            if tooltip is not None:
                buf.write("?", True).write_chat(tooltip)
            else:
                buf.write("?", False)

        return buf
