"""Helper condivisi sulle barre OHLCV live (lezione EXIT-16, 2026-06-05).

La riga -1 di un df di candele e' la candela IN FORMAZIONE finche' non e'
trascorsa la sua durata: valutare segnali/exit-confirm su quella riga
reintroduce la wick-sensitivity che EXIT-16 elimina (audit live: 2 stop su 3
del crash ETH erano wick-stop sulla barra in corso). Questa e' l'UNICA
implementazione della detection — prima era copiata in 4 punti
(strategy_worker, basket_trend_worker, pairs_worker, runner._check_stale_feed)
con una variante hardcoded a 1h: una correzione applicata a una copia e
dimenticata nelle altre reintrodurrebbe il bug in silenzio.
"""
from __future__ import annotations

import time

import numpy as np


def bar_ms_of(ts_ms, window: int = 50) -> int:
    """Durata stimata della barra: mediana dei diff degli ultimi `window`
    timestamp (ms). 0 se la serie e' troppo corta per stimarla."""
    ts = np.asarray(ts_ms, dtype="int64")
    if len(ts) < 2:
        return 0
    return int(np.median(np.diff(ts[-window:])))


def last_bar_is_forming(ts_ms, now_ms: int | None = None) -> bool:
    """True se la riga -1 e' la candela IN CORSO (now < ts[-1] + durata barra)."""
    ts = np.asarray(ts_ms, dtype="int64")
    if len(ts) == 0:
        return False
    bar = bar_ms_of(ts)
    if not bar:
        return False
    if now_ms is None:
        now_ms = int(time.time() * 1000)
    return now_ms < int(ts[-1]) + bar


def last_settled_idx(ts_ms, now_ms: int | None = None) -> int:
    """Indice dell'ultima barra COMPLETATA: -1 se la riga -1 e' chiusa,
    -2 se e' in formazione."""
    return -2 if last_bar_is_forming(ts_ms, now_ms) else -1
