"""Failure bundles are emitted THROUGH the canonical SECTION_ORDER
(TS-27, M2 Wave-2 schema-truth fix).

Every canonical section header appears, in order, in the exact
`=== <name> ===` form — empty sections included — so downstream
tooling grepping via `mgf.common.testing.SECTION_ORDER` matches
every bundle the supervisor writes. Extras (perf) come after.
"""

from __future__ import annotations

import re
from typing import TYPE_CHECKING

from mgf.test_supervisor.records import SECTION_HEADER_FMT, SECTION_ORDER, TestRecord, now_iso
from mgf.test_supervisor.supervisor import ChunkResult, RunConfig, Supervisor, _safe_filename

if TYPE_CHECKING:
    from pathlib import Path


def _write_bundle(tmp_path: Path, *, perf: dict[str, object] | None) -> str:
    cfg = RunConfig(
        repo_root=tmp_path,
        gates_dir=tmp_path / ".gates",
        test_ids=["tests/unit/test_z.py::test_boom"],
        test_markers={},
        run_id="bundle-run",
        pytest_cmd=["true"],
    )
    sup = Supervisor(cfg)
    rec = TestRecord(
        test_id="tests/unit/test_z.py::test_boom",
        outcome="failed",
        severity="FAIL",
        duration_ms=42,
        tier=1,
        markers=("contract",),
        code="AssertionError",
        summary="deliberate",
        detail="Traceback...\nE  AssertionError: deliberate",
        captured_stdout="some stdout",
        captured_stderr="",
        perf=perf,
        run_id="bundle-run",
        ts_iso=now_iso(),
    )
    chunk = ChunkResult(
        test_ids=[rec.test_id],
        junit_xml_path=tmp_path / "junit-0000.xml",
        returncode=1,
        signal_name=None,
        wall_time_s=0.5,
        stdout="",
        stderr="",
        hit_timeout=False,
        pytest_pid=1,
    )
    sup._write_failure_bundle(rec, chunk)
    bundle = sup.last_run_dir / "failures" / f"{_safe_filename(rec.test_id)}.txt"
    return bundle.read_text(encoding="utf-8")


def test_every_canonical_section_in_order(tmp_path: Path) -> None:
    text = _write_bundle(tmp_path, perf=None)
    headers = re.findall(r"^=== (.+) ===$", text, re.MULTILINE)
    assert tuple(headers) == tuple(SECTION_ORDER), (
        f"bundle headers {headers} must be exactly SECTION_ORDER {list(SECTION_ORDER)}"
    )
    # Exact header form (greppability contract).
    for name in SECTION_ORDER:
        assert SECTION_HEADER_FMT.format(name=name) in text
    # Empty sections still carry their header with an (empty) body.
    assert "=== STDERR ===\n(empty)" in text
    # Populated bodies land under their header.
    assert "=== TEST ===\ntests/unit/test_z.py::test_boom" in text
    assert "AssertionError: deliberate" in text


def test_perf_extra_section_comes_after_canonical(tmp_path: Path) -> None:
    perf_payload = {"total_ms": 12.5, "functions": [], "spans": []}
    text = _write_bundle(tmp_path, perf=perf_payload)
    headers = re.findall(r"^=== (.+) ===$", text, re.MULTILINE)
    assert headers[: len(SECTION_ORDER)] == list(SECTION_ORDER)
    assert headers[len(SECTION_ORDER) :] == ["PERF ATTRIBUTION (TS-28)"]


def test_no_perf_no_extra_section(tmp_path: Path) -> None:
    text = _write_bundle(tmp_path, perf=None)
    assert "PERF ATTRIBUTION" not in text
