"""Test the `tinydns-get` tool."""

from __future__ import annotations

import os
import re
import sys
import typing

from . import defs


if typing.TYPE_CHECKING:
    import pathlib


RE_FIRST = re.compile(
    r""" ^
    (?P<rtype> 0 | [1-9][0-9]* )
    \s+
    (?P<name> [A-Za-z0-9/.]+ )
    :
    $ """,
    re.X,
)

RE_SECOND = re.compile(
    r""" ^
    (?: 0 | [1-9][0-9]* ) \s+ bytes
    , \s+
        (?: 0 | [1-9][0-9]* ) \+
        (?: 0 | [1-9][0-9]* ) \+
        (?: 0 | [1-9][0-9]* ) \+
        (?: 0 | [1-9][0-9]* ) \s+ records
    (?:
        , \s+
        [a-z]+
    )*
    $ """,
    re.X,
)

RE_THIRD = re.compile(
    r""" ^
    query: \s+
    (?P<rtype> 0 | [1-9][0-9]* )
    \s+
    (?P<name> [A-Za-z0-9/.]+ )
    $ """,
    re.X,
)


def test_tinydns_query(
    cfg: defs.Config,
    cmd: list[pathlib.Path | str],
    rec: defs.TestRecord,
) -> None:
    """Run a test query and check its output."""
    rdef = defs.TYPES[rec.rtype]
    print(
        f"  - expect {len(rec.answers)} "
        f"answer{'' if len(rec.answers) == 1 else 's'} for "
        f"{rdef.query} {rec.name}",
    )

    cfg.diag("- " + " ".join(map(str, cmd)))
    lines = cfg.check_output(cmd).splitlines()
    if len(lines) < 3 + len(rec.answers):
        sys.exit(f"{cmd!r}: too few lines: {lines!r}")

    match = RE_FIRST.match(lines[0])
    if not (match and int(match.group("rtype")) == rdef.rtype and match.group("name") == rec.name):
        sys.exit(f"{cmd!r}: bad first line: {lines!r}")

    match = RE_SECOND.match(lines[1])
    if not match:
        sys.exit(f"{cmd!r}: bad second line: {lines!r}")

    match = RE_THIRD.match(lines[2])
    if not (match and int(match.group("rtype")) == rdef.rtype and match.group("name") == rec.name):
        sys.exit(f"{cmd!r}: bad query line: {lines!r}")

    ans_lines = lines[3 : 3 + len(rec.answers)]
    more_lines = lines[3 + len(rec.answers) :]
    cfg.diag(f"  - answer lines: {ans_lines!r}")
    cfg.diag(f"  - additional lines: {more_lines!r}")

    if ans_lines != rec.answers:
        sys.exit(
            f"{cmd!r}: bad answers: expected {rec.answers!r}, got {ans_lines!r}, full {lines!r}",
        )

    if rec.answers[0].startswith("authority: "):
        okay = all(line.startswith("additional: ") for line in more_lines)
    else:
        okay = all(line.startswith(("additional: ", "authority: ")) for line in more_lines)
    if not okay:
        sys.exit(f"{cmd!r}: superfluous response: {lines!r}")


def test_tinydns_get(cfg: defs.Config, _tempd: pathlib.Path) -> None:  # noqa: PT019
    """Test the operation of `tinydns-get`."""
    print("\n==== test_tinydns_get")

    tget = cfg.bindir / "tinydns-get"
    if not tget.is_file() or not os.access(tget, os.X_OK):
        sys.exit(f"Not an executable file: {tget}")

    for rec in defs.RECORDS:
        rdef = defs.TYPES[rec.rtype]
        test_tinydns_query(cfg, [tget, rdef.query, rec.name], rec)
