"""Unit tests for V35 market-anchored calibration (pure, no DB/model deps)."""

import os
import sys

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

# tests must be deterministic: never consult the DB source for corrections
os.environ["MARKET_ANCHOR_DB"] = "0"

from models.market_anchor import devig, home_favorite_delta, apply_home_correction


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


def test_devig_sums_to_one_and_orders_by_odds():
    p = devig([2.0, 3.5, 4.0])
    assert p is not None
    assert _approx(sum(p), 1.0)
    assert p[0] > p[1] > p[2]  # shorter odds -> higher prob


def test_devig_removes_bookmaker_margin():
    # 1.61 / 3.15 / 3.77 carries ~20% margin; fair home prob must be BELOW the
    # raw implied 1/1.61, and the three must sum to exactly 1.
    p = devig([1.61, 3.15, 3.77])
    assert p is not None
    assert p[0] < 1.0 / 1.61
    assert _approx(sum(p), 1.0)


def test_devig_rejects_missing_or_placeholder_legs():
    assert devig([1.0, 3.0, 4.0]) is None      # 1.0 leg = no real price
    assert devig([None, 3.0, 4.0]) is None      # missing leg
    assert devig([1.005, 3.0]) is None          # <= 1.01 placeholder
    assert devig([]) is None
    assert devig([1.90, 1.90]) is not None       # valid 2-way


def test_home_correction_only_lifts_favorites():
    assert home_favorite_delta(0.30) == 0.0      # underdog/level: no bias
    assert home_favorite_delta(0.50) > 0.0
    assert home_favorite_delta(0.80) >= home_favorite_delta(0.60)  # monotone


def test_apply_home_correction_keeps_distribution_valid():
    p1, px, p2 = apply_home_correction(0.70, 0.18, 0.12)
    assert p1 > 0.70                              # favourite lifted
    assert _approx(p1 + px + p2, 1.0)             # still a valid distribution
    # underdog vector untouched
    q = apply_home_correction(0.30, 0.30, 0.40)
    assert _approx(q[0], 0.30)


def test_corrections_artifact_loaded_and_fallback():
    import json
    import tempfile
    from models import market_anchor as ma

    # 1) valid artifact -> values come from the file
    with tempfile.NamedTemporaryFile(
        "w", suffix=".json", delete=False, encoding="utf-8"
    ) as fh:
        json.dump(
            {"version": "test", "corrections": {"ms_home": [
                {"lo": 0.60, "hi": 0.70, "delta": 0.042},
            ]}},
            fh,
        )
        path = fh.name
    try:
        os.environ["MARKET_ANCHOR_CORRECTIONS_PATH"] = path
        ma.reload_corrections()
        assert _approx(ma.home_favorite_delta(0.65), 0.042)
        # band not in the artifact -> the STATIC PRIOR applies (silence must
        # not erase proven knowledge); 0.45-0.55 static prior is 0.010
        assert _approx(ma.home_favorite_delta(0.50), 0.010)

        # 2) malformed artifact -> static fallback, never crashes
        with open(path, "w", encoding="utf-8") as fh2:
            fh2.write("{not json")
        ma.reload_corrections()
        assert ma.home_favorite_delta(0.65) > 0.0    # fallback band value
        assert _approx(ma.home_favorite_delta(0.65), 0.028)
    finally:
        os.environ.pop("MARKET_ANCHOR_CORRECTIONS_PATH", None)
        ma.reload_corrections()
        os.unlink(path)


def test_away_corrections_only_from_artifact():
    import json
    import tempfile
    from models import market_anchor as ma

    # without an artifact: away correction must be ZERO (earned, not assumed).
    # (Point the env path at a nonexistent file: the repo now SHIPS a fitted
    # artifact, so "no artifact" must be simulated explicitly.)
    os.environ["MARKET_ANCHOR_CORRECTIONS_PATH"] = os.path.join(
        os.path.dirname(__file__), "does_not_exist.json"
    )
    ma.reload_corrections()
    assert ma.away_favorite_delta(0.65) == 0.0
    base = ma.apply_corrections(0.20, 0.20, 0.60)
    assert _approx(base[2], 0.60)  # away untouched without artifact

    with tempfile.NamedTemporaryFile(
        "w", suffix=".json", delete=False, encoding="utf-8"
    ) as fh:
        json.dump(
            {"version": "t2", "corrections": {
                "ms_home": [{"lo": 0.45, "hi": 0.55, "delta": 0.010}],
                "ms_away": [{"lo": 0.55, "hi": 0.65, "delta": 0.020}],
            }},
            fh,
        )
        path = fh.name
    try:
        os.environ["MARKET_ANCHOR_CORRECTIONS_PATH"] = path
        ma.reload_corrections()
        assert _approx(ma.away_favorite_delta(0.60), 0.020)
        p1, px, p2 = ma.apply_corrections(0.20, 0.20, 0.60)
        assert p2 > 0.60                      # away favourite lifted
        assert _approx(p1 + px + p2, 1.0)     # still a valid distribution
        assert p1 < 0.20 and px < 0.20        # others renormalised down
    finally:
        os.environ.pop("MARKET_ANCHOR_CORRECTIONS_PATH", None)
        ma.reload_corrections()
        os.unlink(path)


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.")
