"""
Known-case tests for the backtesting performance/robustness engines (StockLab overhaul, Parts
20-21). Both modules are pure numerical engines with no DB/replay dependency — see their module
docstrings for what they do NOT cover (the point-in-time replay loop itself, replay.py, is
NOT IMPLEMENTED and has no tests because it has no code beyond a documented exception).
"""
from __future__ import annotations

from app.engines.backtesting.performance import compute_performance_report
from app.engines.backtesting.robustness import assess_robustness


def test_performance_report_hand_computed_total_return_and_cagr():
    # Two periods: +10%, then +10% again -> total return = 1.1*1.1-1 = 0.21
    report = compute_performance_report([0.10, 0.10], periods_per_year=1.0)
    assert abs(report.total_return - 0.21) < 1e-9
    # 2 periods at 1 period/year -> years=2 -> CAGR = 1.21^(1/2)-1 = 0.10 exactly (symmetric case)
    assert abs(report.cagr - 0.10) < 1e-9


def test_performance_report_max_drawdown_hand_computed():
    # Equity path: 1.0 -> 1.20 (+20%) -> 0.90 (-25% from peak 1.20) -> 1.08 (+20%)
    report = compute_performance_report([0.20, -0.25, 0.20], periods_per_year=1.0)
    assert abs(report.max_drawdown - (-0.25)) < 1e-9


def test_performance_report_win_rate_and_avg_winner_loser():
    report = compute_performance_report(
        [0.01] * 4, periods_per_year=12,
        trade_returns=[0.20, 0.10, -0.05, -0.15, 0.30],
    )
    assert abs(report.win_rate - 3 / 5) < 1e-9
    assert abs(report.avg_winner - (0.20 + 0.10 + 0.30) / 3) < 1e-9
    assert abs(report.avg_loser - (-0.05 - 0.15) / 2) < 1e-9


def test_performance_report_beta_one_matches_benchmark_exactly():
    # Strategy returns identical to benchmark -> beta = 1.0, alpha = 0.0
    returns = [0.02, -0.01, 0.03, 0.00, 0.015]
    report = compute_performance_report(returns, periods_per_year=12, benchmark_period_returns=returns)
    assert abs(report.beta - 1.0) < 1e-9
    assert abs(report.alpha_annualized - 0.0) < 1e-9


def test_performance_report_empty_series_is_none_not_zero():
    report = compute_performance_report([])
    assert report.periods == 0
    assert report.cagr is None
    assert report.total_return is None


def test_robustness_low_variance_across_parameter_sets_is_low_risk():
    report = assess_robustness({"base": 0.12, "mos_plus_2pp": 0.121, "mos_minus_2pp": 0.119, "weight_shift": 0.118})
    assert report.overfit_risk == "LOW"


def test_robustness_high_variance_across_parameter_sets_is_high_risk():
    report = assess_robustness({"base": 0.30, "mos_plus_2pp": 0.05, "mos_minus_2pp": -0.10, "weight_shift": 0.40})
    assert report.overfit_risk == "HIGH"


def test_robustness_too_few_parameter_sets_is_insufficient_data_not_a_guess():
    report = assess_robustness({"base": 0.12, "variant": 0.13})
    assert report.overfit_risk == "INSUFFICIENT_DATA"
    assert report.metric_mean is None


ALL_TESTS = [obj for name, obj in list(globals().items()) if name.startswith("test_") and callable(obj)]

if __name__ == "__main__":
    passed, failed = 0, []
    for fn in ALL_TESTS:
        try:
            fn()
            passed += 1
            print(f"PASS  {fn.__name__}")
        except AssertionError as e:
            failed.append(fn.__name__)
            print(f"FAIL  {fn.__name__}: {e}")
    print(f"\n{passed}/{len(ALL_TESTS)} passed")
    if failed:
        raise SystemExit(1)
