"""STALE_FEED (2026-06-05): alert quando il feed e' flat da >= 2 barre 1h complete,
e al risveglio col gap %. Solo osservabilita': nessun effetto sui worker."""
import pandas as pd
from src.portfolio.runner import _check_stale_feed


def _df(closes_completed, forming=None, price0=100.0):
    """Serie 1h: barre complete con i close dati (flat = ripete il precedente
    con O=H=L=C), piu' eventuale candela in corso (timestamp = ora corrente)."""
    end_ms = int(pd.Timestamp.now(tz="UTC").floor("h").timestamp() * 1000)
    vals = list(closes_completed) + ([forming] if forming is not None else [])
    n = len(vals)
    rows = []
    for j, v in enumerate(vals):
        ts = end_ms - (n - 1 - j) * 3_600_000
        rows.append({"timestamp": ts, "open": v, "high": v, "low": v, "close": v, "volume": 0.0})
    # rendi NON-flat le barre che cambiano prezzo rispetto alla precedente
    for j in range(1, n):
        if rows[j]["close"] != rows[j - 1]["close"]:
            rows[j]["high"] = rows[j]["close"] * 1.001
    return pd.DataFrame(rows)


def _events(monkeypatch):
    sent = []
    import src.live.telegram_notifier as tn
    monkeypatch.setattr(tn, "notify_event", lambda ev, data=None: sent.append((ev, data)))
    return sent


def test_alert_after_two_flat_complete_bars(monkeypatch):
    sent = _events(monkeypatch)
    alerted = set()
    closes = [100 + i for i in range(10)] + [110.0, 110.0, 110.0]   # 3 flat complete
    _check_stale_feed("ETH", _df(closes, forming=110.0), alerted)
    assert "ETH" in alerted
    assert sent and sent[0][0] == "STALE_FEED" and sent[0][1]["flat_bars_1h"] >= 2


def test_no_alert_on_live_feed(monkeypatch):
    sent = _events(monkeypatch)
    alerted = set()
    closes = [100 + i for i in range(13)]                            # sempre in movimento
    _check_stale_feed("ETH", _df(closes, forming=113.5), alerted)
    assert not alerted and not sent


def test_recovery_notifies_gap_once(monkeypatch):
    sent = _events(monkeypatch)
    alerted = {"ETH"}                                                # episodio in corso
    closes = [100.0] * 10 + [96.6]                                   # risveglio: gap -3.4%
    _check_stale_feed("ETH", _df(closes, forming=96.5), alerted)
    assert "ETH" not in alerted
    assert sent and sent[-1][1]["status"] == "RIPRESO" and abs(sent[-1][1]["gap_pct"] + 3.4) < 0.1
    # secondo poll: nessun doppio alert
    sent.clear()
    _check_stale_feed("ETH", _df(closes, forming=96.5), alerted)
    assert not sent
