"""Minimalny DER ASN.1 kodek pre RFC 3161 (vendored do verifikatora).

Toto je BAJT-ZA-BAJT zhodna kopia api/app/asn1.py — zamerne duplikovana, aby bol
forenzny verifikator (`verify_chain.py`) sebestacny a NEZAVISEL od beziacej appky
(`app.*`). Cely zmysel nezavisleho verifikatora je, ze dokaz nestoji na rovnakom
kode, ktory data vyrobil; preto si nesieme vlastny uzky ASN.1/TSA stack.

Pokryva len to, co potrebuje overenie RFC 3161 tokenu: dekodovat TimeStampToken
a TSTInfo natolko, aby sme overili messageImprint. Nie je to vseobecny parser —
plne kryptograficke overenie CMS podpisu robi `cryptography` v `_tsa.py`.

Referencie: RFC 3161 (TSTInfo), X.690 (DER).
"""

from __future__ import annotations

# --- DER tagy ---
_INTEGER = 0x02
_BIT_STRING = 0x03
_OCTET_STRING = 0x04
_NULL = 0x05
_OID = 0x06
_SEQUENCE = 0x30
_BOOLEAN = 0x01

# --- DER bitove masky / hranice ---
_SHORT_FORM_MAX = 0x80   # dlzky < 0x80 su short-form (jeden bajt)
_BYTE_MASK = 0xFF
_HIGH_BIT = 0x80         # MSB: long-form indikator / znamienkovy bit / OID continuation
_OID_VALUE_MASK = 0x7F   # 7 datovych bitov na bajt v OID/base-128


def _der_len(length: int) -> bytes:
    """Zakoduj dlzku v DER (short alebo long form)."""
    if length < _SHORT_FORM_MAX:
        return bytes([length])
    out = b""
    while length:
        out = bytes([length & _BYTE_MASK]) + out
        length >>= 8
    return bytes([_HIGH_BIT | len(out)]) + out


class DerNode:
    """Jeden TLV uzol. `content` su raw bajty hodnoty (bez tagu/dlzky)."""

    __slots__ = ("content", "tag")

    def __init__(self, tag: int, content: bytes) -> None:
        """Vytvor uzol z tagu a raw obsahu."""
        self.tag = tag
        self.content = content

    def children(self) -> list[DerNode]:
        """Parsuj vnoreny obsah (pre constructed tagy)."""
        return parse_all(self.content)

    def as_int(self) -> int:
        """Interpretuj obsah ako big-endian unsigned integer."""
        return int.from_bytes(self.content, "big")


def _read_len(data: bytes, pos: int) -> tuple[int, int]:
    """Precitaj DER dlzku od `pos`. Vrati (dlzka, novy_pos)."""
    first = data[pos]
    pos += 1
    if first < _SHORT_FORM_MAX:
        return first, pos
    n = first & _OID_VALUE_MASK
    length = int.from_bytes(data[pos : pos + n], "big")
    return length, pos + n


def parse_one(data: bytes, pos: int = 0) -> tuple[DerNode, int]:
    """Parsuj jeden TLV od `pos`. Vrati (node, novy_pos)."""
    tag = data[pos]
    length, pos = _read_len(data, pos + 1)
    content = data[pos : pos + length]
    return DerNode(tag, content), pos + length


def parse_all(data: bytes) -> list[DerNode]:
    """Parsuj vsetky TLV v `data` po sebe."""
    out: list[DerNode] = []
    pos = 0
    while pos < len(data):
        node, pos = parse_one(data, pos)
        out.append(node)
    return out


def decode_oid(content: bytes) -> str:
    """Dekoduj OID hodnotu (bez tagu) na bodkovy retazec."""
    first = content[0]
    parts = [str(first // 40), str(first % 40)]
    value = 0
    for byte in content[1:]:
        value = (value << 7) | (byte & _OID_VALUE_MASK)
        if not byte & _HIGH_BIT:
            parts.append(str(value))
            value = 0
    return ".".join(parts)
