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

import os
import pathlib
import re
import sys

from typing import List, Union  # noqa: H301

from . import defs


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[Union[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: "
            f"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: ") or line.startswith("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:
    """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)
