"""Test the `tinydns-data` tool and the produced CDB file."""

from __future__ import annotations

import re
import sys
import typing

from . import defs


if typing.TYPE_CHECKING:
    import pathlib


NULL = bytes([0]).decode(defs.SAFEENC)

RE_CDB_KEY = re.compile(
    r""" ^
    [+]
    (?P<keylen> 0 | [1-9][0-9]* )
    ,
    (?P<vallen> 0 | [1-9][0-9]* )
    :
    (?P<rest> .* )
    $ """,
    re.X | re.S,
)


def cdb_line(match: re.Match[str]) -> str:
    """Parse a single line of `cdb -d` output."""
    keylen, vallen = int(match.group("keylen")), int(match.group("vallen"))
    if keylen < 1 or vallen < 1:
        sys.exit(f"cdbdump: klen {keylen} or vlen {vallen} cannot be zero")
    dump = match.group("rest")
    if len(dump) < keylen + 2 + vallen + 1:
        sys.exit(f"cdbdump: klen {keylen} vlen {vallen} rlen {len(dump)}")

    key, sep, val, eol, dump = (
        dump[:keylen],
        dump[keylen : keylen + 2],
        dump[keylen + 2 : keylen + 2 + vallen],
        dump[keylen + 2 + vallen : keylen + 2 + vallen + 1],
        dump[keylen + 2 + vallen + 1 :],
    )
    if not (key.endswith(NULL) and sep == "->" and eol == "\n"):
        sys.exit(f"cdbdump: bad: {key!r} {sep!r} {val!r} {eol!r} {dump!r}")

    key = key[:-1]
    name_enc = key
    name = []
    while name_enc:
        glen = name_enc[0].encode(defs.SAFEENC)[0]
        if len(name_enc) < glen + 1:
            sys.exit(f"cdbdump: key {key!r} glen {glen}")
        name.append(name_enc[1 : glen + 1])
        name_enc = name_enc[glen + 1 :]

    rectype = val[:2].encode(defs.SAFEENC)
    print(f"key {key!r} name {'.'.join(name)} record type {rectype[0] * 256 + rectype[1]}")

    return dump


def test_tinydns_data(cfg: defs.Config, tempd: pathlib.Path) -> None:
    """Test the creation of the data.cdb file."""
    print("\n==== test_tinydns_data")
    data = tempd / "data"
    data_cdb = data.with_suffix(".cdb")
    if not data.is_file():
        sys.exit(f"Expected {data} to be a file")
    if data_cdb.exists():
        sys.exit(f"Did not expect {data_cdb} to exist")

    tdata = cfg.sbindir / "tinydns-data"
    outp = cfg.check_output([tdata])
    if outp:
        sys.exit(f"{tdata!r} produced output: {outp!r}")

    if not data_cdb.is_file():
        sys.exit(f"{tdata!r} did not create {data_cdb}")

    dump = cfg.check_output(["cdb", "-d", "--", data_cdb], encoding=defs.SAFEENC)
    while match := RE_CDB_KEY.match(dump):
        dump = cdb_line(match)

    if dump != "\n":
        sys.exit(f"cdbdump: leftover {dump!r}")
