"""Unit tests for ``mgf-fed feedback`` (FB-05 outbox relay)."""

from __future__ import annotations

from pathlib import Path

from mgf.fed import _feedback
from mgf.fed._feedback import (
    _next_paper_number,
    _parse_outbox,
    _render_inbox_entry,
    run_feedback,
    scan,
)
from mgf.fed._roster import Member

OUTBOX = """# pending-feedback → mgf-common

> **Outbox.** Drafted here, destined for mgf-common.

## Pending

### PAPER (→ mgf-common) — doctor should report N/A on non-Python members
- **Severity:** 🟢 Nice-to-have
- **Filed by:** mgf-standard (conformance sweep) on 2026-06-07
- **What hurts:** `doctor --standards` exits non-zero on the Zig members.
- **Suggested shape:** detect non-Python shape → emit N/A, exit 0.
"""


def test_parse_outbox_extracts_fields() -> None:
    papers = _parse_outbox(OUTBOX, "mgf-standard", "mgf-common", Path("mgf-common.md"))
    assert len(papers) == 1
    p = papers[0]
    # exact: the title must NOT bleed in the "(→ mgf-common)" prefix (the spaced-dash separator)
    assert p.title == "doctor should report N/A on non-Python members"
    assert "🟢" in p.severity
    assert "mgf-standard" in p.origin and "2026-06-07" in p.origin
    assert p.source == "mgf-standard" and p.target == "mgf-common"


def test_next_paper_number() -> None:
    assert _next_paper_number("### PAPER-01\nfoo\n### PAPER-07 — x\n") == 8
    assert _next_paper_number("no papers yet") == 1


def test_render_inbox_entry_is_fb02_with_xref() -> None:
    p = _parse_outbox(OUTBOX, "mgf-standard", "mgf-common", Path("mgf-common.md"))[0]
    entry = _render_inbox_entry(p, 12)
    assert "### PAPER-12 —" in entry
    assert "| Status | OPEN |" in entry
    assert "| Submitted | 2026-06-07 |" in entry  # date lifted from the Origin line
    assert "pending-feedback/mgf-common.md" in entry  # FB-01 cross-reference
    assert "What hurts" in entry  # body preserved verbatim


def _fake_fleet(tmp_path: Path, monkeypatch) -> None:
    (tmp_path / "mgf-standard" / "pending-feedback").mkdir(parents=True)
    (tmp_path / "mgf-standard" / "pending-feedback" / "mgf-common.md").write_text(OUTBOX, "utf-8")
    (tmp_path / "mgf-common").mkdir()
    (tmp_path / "mgf-common" / "FEEDBACK.md").write_text(
        "# Feedback\n\n### PAPER-03 — old\n", "utf-8"
    )
    fleet = [
        Member(repo="mgf-standard", lang="python", registry_version="0", root=tmp_path),
        Member(repo="mgf-common", lang="python", registry_version="0", root=tmp_path),
    ]
    monkeypatch.setattr(_feedback, "members", lambda base: fleet)


def test_scan_finds_unrelayed(tmp_path: Path, monkeypatch) -> None:
    _fake_fleet(tmp_path, monkeypatch)
    papers = scan(tmp_path)
    assert len(papers) == 1 and papers[0].target == "mgf-common"


def test_check_gate_then_relay_then_idempotent(tmp_path: Path, monkeypatch) -> None:
    _fake_fleet(tmp_path, monkeypatch)
    # the gate: un-relayed feedback → non-zero
    assert run_feedback(root=tmp_path) == 1
    # dry-run writes nothing
    assert run_feedback(relay=True, dry_run=True, root=tmp_path) == 0
    assert not (tmp_path / "mgf-standard" / "pending-feedback" / "relayed").exists()
    # relay applies: next number after PAPER-03 is PAPER-04
    assert run_feedback(relay=True, root=tmp_path) == 0
    fb = (tmp_path / "mgf-common" / "FEEDBACK.md").read_text(encoding="utf-8")
    assert "### PAPER-04 —" in fb
    relayed = tmp_path / "mgf-standard" / "pending-feedback" / "relayed" / "mgf-common-PAPER-04.md"
    assert relayed.is_file()
    # idempotent: the source paper moved to relayed/ → re-scan is clean (gate passes)
    assert run_feedback(root=tmp_path) == 0
