"""Unit tests for V36 market-anchored score matrix (pure, no DB/model deps)."""

import os
import sys

sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))

from models.score_matrix import (
    MAX_GOALS,
    _raw_matrix,
    _outcome_sums,
    build_calibrated_score_package,
    ipf_to_outcomes,
    split_lambdas,
    top_scores,
    total_lambda_from_over25,
)


def _approx(a, b, tol=1e-6):
    return abs(a - b) <= tol


def test_total_lambda_solver_roundtrip():
    import math
    for t_true in (1.5, 2.4, 3.5):
        p_over = 1.0 - math.exp(-t_true) * (1 + t_true + t_true * t_true / 2)
        assert _approx(total_lambda_from_over25(p_over), t_true, 1e-3)


def test_split_matches_win_gap_direction():
    lh, la = split_lambdas(2.6, 0.60, 0.18)   # strong home side
    assert lh > la
    lh2, la2 = split_lambdas(2.6, 0.18, 0.60)  # strong away side
    assert la2 > lh2


def test_ipf_makes_matrix_exactly_consistent_with_1x2():
    p1, px, p2 = 0.62, 0.21, 0.17
    lh, la = split_lambdas(2.7, p1, p2)
    mat = ipf_to_outcomes(_raw_matrix(lh, la), p1, px, p2)
    w, d, l = _outcome_sums(mat)
    assert _approx(w, p1, 1e-9) and _approx(d, px, 1e-9) and _approx(l, p2, 1e-9)


def test_top_scores_sorted_and_shaped():
    mat = _raw_matrix(1.6, 1.1)
    top = top_scores(mat, 5)
    assert len(top) == 5
    probs = [t["prob"] for t in top]
    assert probs == sorted(probs, reverse=True)
    assert all("-" in t["score"] for t in top)


def test_package_full_fields_and_consistency():
    pkg = build_calibrated_score_package(0.526, 0.258, 0.216, 0.55)
    assert pkg["ft"] and pkg["ht"]
    assert pkg["xg_home"] > pkg["xg_away"]          # home is favourite
    assert _approx(pkg["xg_total"], pkg["xg_home"] + pkg["xg_away"], 0.02)
    assert len(pkg["scenario_top5"]) == 5
    assert pkg["calibration_source"] == "market_anchor_v36_score"
    # HT must be a lower-scoring line than FT on average
    fh, fa = map(int, str(pkg["ft"]).split("-"))
    hh, ha = map(int, str(pkg["ht"]).split("-"))
    assert hh + ha <= fh + fa


def test_ht_ipf_applied_when_probs_given():
    base = build_calibrated_score_package(0.40, 0.30, 0.30, 0.50)
    forced = build_calibrated_score_package(
        0.40, 0.30, 0.30, 0.50, ht_probs=(0.05, 0.90, 0.05)
    )
    # forcing a near-certain HT draw must make the modal HT score a draw line
    hh, ha = map(int, str(forced["ht"]).split("-"))
    assert hh == ha
    assert base["ft"] == forced["ft"]  # FT untouched by HT anchoring


if __name__ == "__main__":
    fns = [v for k, v in sorted(globals().items()) if k.startswith("test_")]
    for fn in fns:
        fn()
        print(f"PASS {fn.__name__}")
    print(f"\nAll {len(fns)} tests passed.")
