from __future__ import annotations

from grantflow.api.public_views_metrics import (
    average_metric,
    accumulate_review_readiness_totals,
    accumulate_stale_comment_bucket_counts,
    build_review_readiness_summary,
    merge_token_counts,
    normalize_top_limit,
    overdue_row_sort_key,
    review_readiness_totals_template,
)


def test_review_readiness_totals_accumulator_counts_fields() -> None:
    totals = review_readiness_totals_template()

    accumulate_review_readiness_totals(
        totals,
        {
            "needs_revision": True,
            "open_critic_findings": 2,
            "high_severity_open_findings": 1,
            "open_review_comments": 5,
            "resolved_review_comments": 3,
            "acknowledged_review_comments": 1,
            "pending_review_comments": 4,
            "overdue_review_comments": 2,
            "stale_open_review_comments": 1,
            "linked_review_comments": 6,
            "orphan_linked_review_comments": 2,
            "low_confidence_citations": 7,
            "fallback_strategy_citations": 8,
        },
    )

    assert totals == {
        "needs_revision_job_count": 1,
        "open_critic_findings": 2,
        "high_severity_open_findings": 1,
        "open_review_comments": 5,
        "resolved_review_comments": 3,
        "acknowledged_review_comments": 1,
        "pending_review_comments": 4,
        "overdue_review_comments": 2,
        "stale_open_review_comments": 1,
        "linked_review_comments": 6,
        "orphan_linked_review_comments": 2,
        "low_confidence_citations": 7,
        "fallback_strategy_citations": 8,
    }


def test_stale_comment_bucket_counts_normalizes_keys() -> None:
    totals: dict[str, int] = {}

    accumulate_stale_comment_bucket_counts(
        totals,
        {
            "comment_triage_summary": {
                "stale_comment_bucket_counts": {
                    " Evidence ": 2,
                    "": 1,
                    "Ops": 3,
                }
            }
        },
    )

    assert totals == {"evidence": 2, "general": 1, "ops": 3}


def test_average_metric_ignores_non_numeric_rows() -> None:
    rows = [
        {"x": 1},
        {"x": 2.0},
        {"x": "3"},
        {"y": 9},
    ]
    assert average_metric(rows, "x") == 1.5
    assert average_metric(rows, "missing") is None


def test_build_review_readiness_summary_computes_rates_and_sorts_buckets() -> None:
    totals = review_readiness_totals_template()
    totals["needs_revision_job_count"] = 1
    totals["open_critic_findings"] = 3
    totals["high_severity_open_findings"] = 2
    totals["open_review_comments"] = 4
    totals["resolved_review_comments"] = 2
    totals["acknowledged_review_comments"] = 1
    totals["pending_review_comments"] = 3
    totals["overdue_review_comments"] = 1
    totals["stale_open_review_comments"] = 2
    totals["linked_review_comments"] = 5
    totals["orphan_linked_review_comments"] = 1

    summary = build_review_readiness_summary(
        totals,
        job_count=2,
        triage_summary={"urgent": 1},
        stale_comment_bucket_counts={"ops": 1, "evidence": 2},
    )

    assert summary["needs_revision_rate"] == 0.5
    assert summary["open_critic_findings_per_job_avg"] == 1.5
    assert summary["high_severity_open_findings_per_job_avg"] == 1.0
    assert summary["triage_summary"] == {"urgent": 1}
    assert list(summary["stale_comment_bucket_counts"].keys()) == ["evidence", "ops"]


def test_merge_token_counts_normalizes_and_coerces_numbers() -> None:
    target: dict[str, int] = {"high": 1}
    merge_token_counts(target, {" High ": "2", "": "3.9", "low": True})
    assert target == {"high": 3, "unknown": 3, "low": 1}


def test_overdue_row_sort_key_handles_numeric_and_invalid_values() -> None:
    assert overdue_row_sort_key({"overdue_hours": "2.5", "due_at": "2026-01-01T00:00:00Z"}) == (
        2.5,
        "2026-01-01T00:00:00Z",
    )
    assert overdue_row_sort_key({"overdue_hours": "n/a", "due_at": None}) == (-1.0, "")


def test_normalize_top_limit_handles_common_inputs() -> None:
    assert normalize_top_limit(10) == 10
    assert normalize_top_limit(0) == 1
    assert normalize_top_limit("4") == 4
    assert normalize_top_limit("4.9") == 4
    assert normalize_top_limit(None) == 1
