"""Beweist, dass `core/sr_levels.py` bitgenau das rechnet, was bis 2026-08-07
inline in `engine._draw_levels` stand — und dass der Backtest-Nachbau ABWICH.

⚠ `_draw_levels` ist LIVE-Code: er bestimmt die gezeichneten S/R-Linien, den
Dashboard-Wert UND das Level, das der P(break)-Auto-Close bewertet. Eine
Refaktorierung dort darf das Verhalten nicht anfassen.
"""
import random

from core.sr_levels import cluster, halten, linien, naechste


# ── eingefrorene Fassung, wörtlich aus `engine._draw_levels` (vor dem Umbau) ──
def _alt_cluster(vals, atr):
    out = []
    for v in sorted(vals):
        if out and v - out[-1][-1] <= 0.5 * atr:
            out[-1].append(v)
        else:
            out.append([v])
    return [round(sum(g) / len(g), 3) for g in out]


def _alt_hold(new, old, bid, atr, is_res):
    if old is None:
        return new
    m = 0.10 * atr
    broken = (bid > old + m) if is_res else (bid < old - m)
    if broken:
        return new
    if (new is not None and abs(old - bid) > 1.5 * atr
            and abs(new - bid) < abs(old - bid) - 0.5 * atr):
        return new
    return old


# ── der ABWEICHENDE Backtest-Nachbau (gemischter Pool, ohne Rundung) ─────────
def _nachbau_cluster(levels, atr):
    if not levels:
        return []
    out = []; grp = [levels[0]]
    for x in levels[1:]:
        if x - grp[-1] <= 0.5 * atr:
            grp.append(x)
        else:
            out.append(sum(grp) / len(grp)); grp = [x]
    out.append(sum(grp) / len(grp))
    return out


def _pivots(seed, n=40):
    rnd = random.Random(seed)
    basis = 75.0 + rnd.uniform(-3, 3)
    ph = sorted(round(basis + rnd.uniform(0.0, 3.0), 3) for _ in range(n))
    pl = sorted(round(basis - rnd.uniform(0.0, 3.0), 3) for _ in range(n))
    return ph, pl


def test_cluster_bitgenau():
    for seed in range(300):
        ph, pl = _pivots(seed)
        atr = 0.12 + (seed % 30) * 0.01
        assert cluster(ph, atr) == _alt_cluster(ph, atr), f"seed {seed}"
        assert cluster(pl, atr) == _alt_cluster(pl, atr), f"seed {seed}"


def test_linien_und_auswahl_bitgenau():
    """Der ganze Live-Pfad: getrennt clustern → zusammenführen → nächste wählen."""
    for seed in range(300):
        ph, pl = _pivots(seed)
        atr = 0.12 + (seed % 30) * 0.01
        px = 75.0 + (seed % 11) * 0.2
        alt = _alt_cluster(ph, atr) + _alt_cluster(pl, atr)
        r_alt = min((p for p in alt if p > px), default=None)
        s_alt = max((p for p in alt if p < px), default=None)
        r_neu, s_neu = naechste(linien(ph, pl, atr), px)
        assert (r_neu, s_neu) == (r_alt, s_alt), f"seed {seed}"


def test_hysterese_bitgenau():
    rnd = random.Random(7)
    faelle = 0
    for seed in range(400):
        atr = 0.1 + (seed % 25) * 0.02
        px = 75.0 + rnd.uniform(-2, 2)
        for alt_l in (None, px + rnd.uniform(-3, 3)):
            neu = px + rnd.uniform(-3, 3)
            for is_res in (True, False):
                a = halten(neu, alt_l, px, atr, is_res)
                b = _alt_hold(neu, alt_l, px, atr, is_res)
                assert a == b, f"seed {seed}"
                faelle += 1
    assert faelle > 1000


def test_nachbau_wich_wirklich_ab():
    """⚠ Gegenprobe: der Backtest-Nachbau (gemischter Pool) liefert NICHT
    dasselbe. Ohne diesen Test wäre nicht belegt, dass es überhaupt etwas zu
    beheben gab — und ein Test, der nicht scheitern kann, ist wertlos."""
    abweichungen = 0
    for seed in range(300):
        ph, pl = _pivots(seed)
        atr = 0.12 + (seed % 30) * 0.01
        live = sorted(linien(ph, pl, atr))
        nachbau = sorted(_nachbau_cluster(sorted(ph + pl), atr))
        if [round(x, 3) for x in nachbau] != live:
            abweichungen += 1
    assert abweichungen > 0, "Nachbau und Live sind gleich — dann gab es nichts zu beheben"


def test_cluster_leer():
    assert cluster([], 0.2) == []
    assert linien([], [], 0.2) == []
    assert naechste([], 75.0) == (None, None)
