"""Unit tests for the extraction_coverage block in the report summary.

Both the classic pipeline and the agent runner build their summary via
backend.pipeline.report.build_report, so unit tests on that function cover
every summary-producing path.
"""

from backend.pipeline.report import build_report


def _sheet(page, coverage=None, assertions=None):
    sheet = {
        "page_number": page,
        "sheet_number": f"S{page:03d}",
        "discipline": "S",
        "assertions": assertions if assertions is not None else [
            {"text": "NOTE ALPHA", "object_type": "note"},
            {"text": "NOTE BETA", "object_type": "note"},
        ],
    }
    if coverage is not None:
        sheet["coverage"] = coverage
    return sheet


def _cov(total, covered):
    return {
        "total_lines": total,
        "covered_lines": covered,
        "ratio": covered / total if total else 0.0,
    }


def test_extraction_coverage_omitted_without_coverage_data():
    report = build_report(conflicts=[], sheets=[_sheet(1), _sheet(2)], clusters=[])
    assert "extraction_coverage" not in report["summary"]


def test_extraction_coverage_healthy():
    sheets = [_sheet(1, _cov(100, 95)), _sheet(2, _cov(80, 76))]
    report = build_report(conflicts=[], sheets=sheets, clusters=[])
    cov = report["summary"]["extraction_coverage"]
    assert cov["pages_measured"] == 2
    assert cov["pages_below_floor"] == []
    assert cov["fallback_pages"] == []
    assert cov["mean_ratio"] == round((0.95 + 0.95) / 2, 3)


def test_extraction_coverage_flags_below_floor():
    sheets = [
        _sheet(1, _cov(100, 95)),
        _sheet(2, _cov(100, 40)),   # ratio 0.4 < 0.6 floor
        _sheet(3, _cov(100, 59)),   # ratio 0.59 < 0.6 floor
    ]
    report = build_report(conflicts=[], sheets=sheets, clusters=[])
    cov = report["summary"]["extraction_coverage"]
    assert cov["pages_measured"] == 3
    assert cov["pages_below_floor"] == [2, 3]
    assert cov["mean_ratio"] == round((0.95 + 0.4 + 0.59) / 3, 3)


def test_extraction_coverage_flags_fallback_pages():
    fallback_assertions = [
        {"text": "NOTE ALPHA", "object_type": "note"},
        {"text": "NOTE BETA", "object_type": "note",
         "grounding": "text_layer_fallback"},
    ]
    sheets = [
        _sheet(1, _cov(100, 90), assertions=fallback_assertions),
        _sheet(2, _cov(100, 90)),
    ]
    report = build_report(conflicts=[], sheets=sheets, clusters=[])
    cov = report["summary"]["extraction_coverage"]
    assert cov["fallback_pages"] == [1]


def test_extraction_coverage_mixed_sheets_only_counts_measured():
    # Sheet 2 has no coverage dict (e.g. scanned page / older path).
    sheets = [_sheet(1, _cov(100, 50)), _sheet(2)]
    report = build_report(conflicts=[], sheets=sheets, clusters=[])
    cov = report["summary"]["extraction_coverage"]
    assert cov["pages_measured"] == 1
    assert cov["pages_below_floor"] == [1]
    assert cov["mean_ratio"] == 0.5
