"""Sentence and Pair types mirroring the RouterOS API protocol data unit."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import List


@dataclass
class Pair:
    """A single key-value pair within a sentence."""

    key: str
    value: str

    def __str__(self) -> str:
        return f"{self.key!r}={self.value!r}"


@dataclass
class Sentence:
    """A RouterOS API sentence (the basic unit of communication).

    Attributes:
        word:  The sentence type word, e.g. ``!re``, ``!done``, ``!trap``,
               ``!fatal``, ``!empty``, or a command like ``/ip/address/print``.
        tag:   The correlation tag for async requests (value of ``.tag=`` word).
        pairs: Ordered list of :class:`Pair` objects (preserves insertion order).
        map:   Dictionary for fast key-based value lookup.
    """

    word: str = ""
    tag: str = ""
    pairs: List[Pair] = field(default_factory=list)
    map: dict[str, str] = field(default_factory=dict)

    # ------------------------------------------------------------------
    # Factory
    # ------------------------------------------------------------------

    @classmethod
    def from_words(cls, words: List[str]) -> "Sentence":
        """Build a :class:`Sentence` from a raw list of string words.

        Word parsing rules (same as the Go reference implementation):

        * The first word becomes :attr:`word`.
        * Words starting with ``.tag=`` set :attr:`tag`.
        * Words starting with ``=`` are key-value pairs: ``=key=value`` or
          ``=key`` (value defaults to ``""``).
        * Any other word raises :class:`ValueError`.
        """
        sen = cls()
        for raw in words:
            if sen.word == "":
                sen.word = raw
                continue
            if raw.startswith(".tag="):
                sen.tag = raw[5:]
                continue
            if raw.startswith("="):
                rest = raw[1:]
                if "=" in rest:
                    key, value = rest.split("=", 1)
                else:
                    key, value = rest, ""
                p = Pair(key, value)
                sen.pairs.append(p)
                sen.map[key] = value
                continue
            raise ValueError(f"invalid RouterOS sentence word: {raw!r}")
        return sen

    # ------------------------------------------------------------------
    # Helpers
    # ------------------------------------------------------------------

    def __str__(self) -> str:
        return f"{self.word} @{self.tag} {self.pairs!r}"
