# ruff: noqa: N802, N815, N999
"""Minimal WAProto subset with real protobuf wire encoding.

This module intentionally implements only fields currently used by waton:
- Message.conversation
- Message.extendedTextMessage.text
- Message.reactionMessage.{key,text}
- Message.deviceSentMessage.{destinationJid,message}
"""

from __future__ import annotations

from dataclasses import dataclass, field

from .wire import encode_bool, encode_len_delimited, encode_string, iter_fields


@dataclass
class MessageKey:
    remoteJid: str = ""
    fromMe: bool = False
    id: str = ""
    participant: str = ""

    def SerializeToString(self) -> bytes:
        return b"".join(
            (
                encode_string(1, self.remoteJid),
                encode_bool(2, self.fromMe if self.fromMe else None),
                encode_string(3, self.id),
                encode_string(4, self.participant),
            )
        )

    def ParseFromString(self, data: bytes) -> None:
        for field_no, wire_type, value in iter_fields(data):
            if wire_type == 2 and field_no == 1:
                self.remoteJid = bytes(value).decode("utf-8", errors="ignore")
            elif wire_type == 0 and field_no == 2:
                self.fromMe = bool(int(value))
            elif wire_type == 2 and field_no == 3:
                self.id = bytes(value).decode("utf-8", errors="ignore")
            elif wire_type == 2 and field_no == 4:
                self.participant = bytes(value).decode("utf-8", errors="ignore")


@dataclass
class ReactionMessage:
    key: MessageKey = field(default_factory=MessageKey)
    text: str = ""

    def SerializeToString(self) -> bytes:
        key_payload = self.key.SerializeToString()
        return b"".join(
            (
                encode_len_delimited(1, key_payload) if key_payload else b"",
                encode_string(2, self.text),
            )
        )

    def ParseFromString(self, data: bytes) -> None:
        for field_no, wire_type, value in iter_fields(data):
            if wire_type == 2 and field_no == 1:
                self.key.ParseFromString(bytes(value))
            elif wire_type == 2 and field_no == 2:
                self.text = bytes(value).decode("utf-8", errors="ignore")


@dataclass
class ExtendedTextMessage:
    text: str = ""

    def SerializeToString(self) -> bytes:
        return encode_string(1, self.text)

    def ParseFromString(self, data: bytes) -> None:
        for field_no, wire_type, value in iter_fields(data):
            if wire_type == 2 and field_no == 1:
                self.text = bytes(value).decode("utf-8", errors="ignore")


@dataclass
class ImageMessage:
    url: str = ""
    mimetype: str = ""
    caption: str = ""
    fileSha256: bytes = b""
    fileLength: int = 0
    height: int = 0
    width: int = 0
    mediaKey: bytes = b""
    fileEncSha256: bytes = b""
    directPath: str = ""

    def SerializeToString(self) -> bytes:
        parts: list[bytes] = []
        if self.url:
            parts.append(encode_string(1, self.url))
        if self.mimetype:
            parts.append(encode_string(2, self.mimetype))
        if self.caption:
            parts.append(encode_string(3, self.caption))
        if self.fileSha256:
            parts.append(encode_len_delimited(4, self.fileSha256))
        if self.fileLength:
            parts.append(encode_string(5, str(self.fileLength)))
        if self.mediaKey:
            parts.append(encode_len_delimited(8, self.mediaKey))
        if self.fileEncSha256:
            parts.append(encode_len_delimited(9, self.fileEncSha256))
        if self.directPath:
            parts.append(encode_string(10, self.directPath))
        return b"".join(parts)

    def ParseFromString(self, data: bytes) -> None:
        for field_no, wire_type, value in iter_fields(data):
            if wire_type == 2 and field_no == 1:
                self.url = bytes(value).decode("utf-8", "ignore")
            elif wire_type == 2 and field_no == 2:
                self.mimetype = bytes(value).decode("utf-8", "ignore")
            elif wire_type == 2 and field_no == 3:
                self.caption = bytes(value).decode("utf-8", "ignore")

class Message:
    class _NoDeviceSentMessage:
        def __init__(self) -> None:
            self.destinationJid = ""
            self.message = None

        def SerializeToString(self) -> bytes:
            return b""

        def ParseFromString(self, data: bytes) -> None:
            _ = data

    class _DeviceSentMessage:
        def __init__(self) -> None:
            self.destinationJid = ""
            self.message = Message(_include_device_sent=False)

        def SerializeToString(self) -> bytes:
            nested = self.message.SerializeToString()
            return b"".join(
                (
                    encode_string(1, self.destinationJid),
                    encode_len_delimited(2, nested) if nested else b"",
                )
            )

        def ParseFromString(self, data: bytes) -> None:
            for field_no, wire_type, value in iter_fields(data):
                if wire_type == 2 and field_no == 1:
                    self.destinationJid = bytes(value).decode("utf-8", errors="ignore")
                elif wire_type == 2 and field_no == 2:
                    self.message.ParseFromString(bytes(value))

    def __init__(self, _include_device_sent: bool = True) -> None:
        self.conversation = ""
        self.extendedTextMessage = ExtendedTextMessage()
        self.imageMessage = ImageMessage()
        self.reactionMessage = ReactionMessage()
        self.deviceSentMessage = (
            Message._DeviceSentMessage() if _include_device_sent else Message._NoDeviceSentMessage()
        )

    def SerializeToString(self) -> bytes:
        ext = self.extendedTextMessage.SerializeToString()
        img = self.imageMessage.SerializeToString()
        react = self.reactionMessage.SerializeToString()
        device_sent = self.deviceSentMessage.SerializeToString()
        return b"".join(
            (
                encode_string(1, self.conversation),
                encode_len_delimited(4, img) if img else b"",
                encode_len_delimited(6, ext) if ext else b"",
                encode_len_delimited(31, device_sent) if device_sent else b"",
                encode_len_delimited(46, react) if react else b"",
            )
        )

    def ParseFromString(self, data: bytes) -> None:
        try:
            for field_no, wire_type, value in iter_fields(data):
                if wire_type != 2:
                    continue
                payload = bytes(value)
                if field_no == 1:
                    self.conversation = payload.decode("utf-8", errors="ignore")
                elif field_no == 4:
                    self.imageMessage.ParseFromString(payload)
                elif field_no == 6:
                    self.extendedTextMessage.ParseFromString(payload)
                elif field_no == 31:
                    self.deviceSentMessage.ParseFromString(payload)
                elif field_no == 46:
                    self.reactionMessage.ParseFromString(payload)
        except Exception:
            self.conversation = data.decode("utf-8", errors="ignore")
