"""Unit tests for `vol_targeted_metrics` — the cockpit's COMPARABLE standalone-sleeve metric.

The cockpit used to show each sleeve's RAW UNSIZED cumulative return (e.g. positioning +4228%), which is
misleading: unsized, and different sleeves span different histories. `vol_targeted_metrics` scales a daily
series to a common annual vol target then annualises, so sleeves are apples-to-apples:
  * scaling to 20% vol then annualising ≈ Sharpe × 0.20 (the geometric drag is small for sane series);
  * maxDD is computed on the SCALED (compounded) series — a consistent risk basis, not the raw maxDD;
  * scale-invariant Sharpe is preserved; degenerate (<2 obs / zero-vol) series → all zeros;
  * deterministic.
Pure — NO network, NO DB.
"""
from __future__ import annotations

import math
import random

from fxhnt.application.bybit_book_eval import (
    _SLEEVE_VOL_TARGET,
    _standalone_sharpe,
    vol_targeted_metrics,
)


def _series(rets: list[float], *, start_day: int = 739_000) -> dict[int, float]:
    return {start_day + i: r for i, r in enumerate(rets)}


def test_ann_return_approx_sharpe_times_vol_target() -> None:
    rng = random.Random(42)
    # ~2 years of daily returns with a positive mean and modest daily vol -> a clean, well-defined Sharpe.
    rets = [0.0008 + rng.gauss(0.0, 0.01) for _ in range(730)]
    series = _series(rets)
    m = vol_targeted_metrics(series, vol_target=0.20)
    sharpe = _standalone_sharpe(series)
    assert m["sharpe"] == sharpe                                   # scale-invariant
    # vol-targeted annual return ~= Sharpe * vol_target (geometric compounding vs arithmetic Sharpe×vol
    # leaves a modest gap; the point is they are the same order, not the misleading 42× raw cumulative).
    assert math.isclose(m["ann_return"], sharpe * 0.20, rel_tol=0.20)
    assert m["vol_target"] == 0.20


def test_maxdd_on_scaled_series_not_raw() -> None:
    # A loud loser run then recovery: the scaled-series maxDD must be on the 20%-vol-scaled curve, so it is
    # bounded and DIFFERENT from the raw cumulative maxDD of a high-vol series.
    rng = random.Random(7)
    rets = [rng.gauss(0.0003, 0.05) for _ in range(500)]           # high raw vol (~95%/yr)
    series = _series(rets)
    m = vol_targeted_metrics(series, vol_target=0.20)
    assert m["max_dd"] <= 0.0
    # raw maxDD (unscaled compounding) is much deeper than the 20%-vol-scaled maxDD.
    raw_eq = 1.0
    raw_peak = 1.0
    raw_dd = 0.0
    for d in sorted(series):
        raw_eq *= (1.0 + series[d])
        raw_peak = max(raw_peak, raw_eq)
        raw_dd = min(raw_dd, raw_eq / raw_peak - 1.0)
    assert m["max_dd"] > raw_dd                                    # scaled DD shallower (less negative)


def test_degenerate_series_return_zeros() -> None:
    assert vol_targeted_metrics({}) == {
        "ann_return": 0.0, "max_dd": 0.0, "sharpe": 0.0, "vol_target": _SLEEVE_VOL_TARGET}
    assert vol_targeted_metrics(_series([0.01])) == {
        "ann_return": 0.0, "max_dd": 0.0, "sharpe": 0.0, "vol_target": _SLEEVE_VOL_TARGET}
    # zero-vol (constant) series -> undefined scaling -> zeros, never a divide-by-zero.
    assert vol_targeted_metrics(_series([0.0, 0.0, 0.0, 0.0])) == {
        "ann_return": 0.0, "max_dd": 0.0, "sharpe": 0.0, "vol_target": _SLEEVE_VOL_TARGET}


def test_deterministic() -> None:
    rng = random.Random(99)
    series = _series([rng.gauss(0.0005, 0.012) for _ in range(400)])
    assert vol_targeted_metrics(series) == vol_targeted_metrics(series)
