"""Doc↔code alignment: TESTING.md's marker/tier truth vs this package.

The M2 Wave-1 recon found THREE different answers for `integration`'s
tier across TESTING.md and the code, a phantom `functional` marker
documented-but-registered-nowhere, and a zombie `slow` — because
nothing pinned doc↔code (PLAN §1.3). This is the code-side half of
the two-sided pin:

- mgf-standard's `scripts/check_testing_doc.py` (invoked by
  `gen_rules_index.py --check`, which rides its pytest steps) checks
  the DOC's internal consistency on every mgf-standard change — and
  compares against `mgf.common.testing` when importable.
- THIS test checks the reverse on every mgf-common change: the
  installed standards corpus (`mgf.standard.read_standard("TESTING")`
  — dev dep, wheel-data or editable fallback) must carry EXACTLY the
  mapping this package ships. A MARKER_TIER change here without a
  corpus follow-up goes red here.

Release-dance guard: a pre-Wave-2 corpus (phantom `functional` row /
`slow` still in the inline block) skips loudly; the pin arms
automatically once mgf-standard >= 0.1.62 (the honest-gate corpus)
is installed.
"""

from __future__ import annotations

import ast
import re

import pytest

from mgf.common.testing import MARKER_TIER, TIERS

mgf_standard = pytest.importorskip(
    "mgf.standard", reason="mgf-standard (dev dep) not installed; doc↔code pin skipped"
)

_DOC = mgf_standard.read_standard("TESTING")

_BLOCK_RE = re.compile(r"MARKER_TIER = (\{.*?\})", re.DOTALL)


def _doc_marker_tier() -> dict[str, int]:
    m = _BLOCK_RE.search(_DOC)
    assert m, "TESTING.md no longer carries the inline MARKER_TIER block (§13.11)"
    parsed = ast.literal_eval(m.group(1))
    assert isinstance(parsed, dict)
    return parsed


_doc_map = _doc_marker_tier()

# Release-dance detection on PARSED structures (a raw substring probe
# would trip on the doc's own strike/migration notes, which naturally
# mention the removed names): pre-Wave-2 = `slow` still mapped in the
# inline block, or a live `| `functional` |` taxonomy-table row.
_functional_row = re.search(r"^\| `functional` \|", _DOC, re.MULTILINE)

if "slow" in _doc_map or _functional_row:  # pragma: no cover - release-dance window
    pytest.skip(
        "installed mgf-standard corpus pre-dates the M2 Wave-2 tier sitting "
        "(TESTING.md still maps `slow` / tabulates `functional`); the doc↔code "
        "pin arms once the honest-gate corpus (mgf-standard >= 0.1.62) is installed",
        allow_module_level=True,
    )


class TestMarkerTierDocMatchesCode:
    def test_inline_block_matches_code_exactly(self) -> None:
        assert _doc_map == dict(MARKER_TIER), (
            "TESTING.md §13.11 inline MARKER_TIER block drifted from "
            f"mgf.common.testing.MARKER_TIER:\n  doc:  {_doc_map}\n"
            f"  code: {dict(MARKER_TIER)}\n"
            "Fix the doc (or the code + doc together) in one commit — "
            "mgf-standard's check_testing_doc.py gates the doc side."
        )

    def test_doc_taxonomy_table_matches_code_keys(self) -> None:
        # Every §13.11 table row's marker (rows like `| \`smoke\` | ...`)
        # that IS a tier-mapped marker must be in the code mapping, and
        # every code marker must appear as a table row. ([a-z0-9_]:
        # `e2e` carries a digit.)
        rows = set(re.findall(r"^\| `([a-z0-9_]+)` \|", _DOC, re.MULTILINE))
        mapped_rows = {r for r in rows if r in MARKER_TIER}
        missing_from_doc = set(MARKER_TIER) - rows
        assert not missing_from_doc, (
            f"markers mapped in code but absent from TESTING.md tables: {missing_from_doc}"
        )
        assert mapped_rows == set(MARKER_TIER)

    def test_doc_tier_budgets_match_code(self) -> None:
        # §19.2's four-tier budget lines pin the same numbers as TIERS.
        for tier in TIERS:
            pattern = re.compile(rf"{tier.name}\b.*?({tier.per_test_seconds:.2f})", re.DOTALL)
            assert pattern.search(_DOC), (
                f"TESTING.md §19.2 no longer states {tier.name}'s per-test "
                f"budget {tier.per_test_seconds:.2f}s"
            )
