"""FEED LIVE EFFIMERO per il segnale SKH01 (book a 230m) — NON tocca i dati certificati su disco.

SKH01 decide su griglia 230m: per eseguirlo fedelmente il segnale serve fresco all'ultima barra
chiusa. Il rebuild certificato (rebuild_history.py) gira 1×/giorno e fa un rebuild COMPLETO (pesante):
girarlo ogni ora sarebbe sbagliato e violerebbe la regola "aggiornare lo storico SOLO con
rebuild_history + certificare". Quindi qui NON scriviamo su disco: carichiamo il 5m CERTIFICATO e gli
appendiamo IN MEMORIA una coda recente presa da Deribit PUBBLICO (ccxt, tokenless, STESSO simbolo
inverse del feed certificato -> prezzi entro ~3 bps). I dati certificati restano la verità su disco;
questa estensione vive solo nel processo live e per il calcolo del segnale.

Robusto ai fallimenti: qualunque errore di rete/fetch -> ritorna il feed certificato invariato (il
runner degrada a "fermo all'ultimo dato certificato", mai opera a cieco). Solo SKH01 ne ha bisogno:
TP01 è giornaliero e gira bene sul feed certificato.
"""
from __future__ import annotations

import time

import pandas as pd

from src.data.downloader import load_data

# STESSO simbolo del feed certificato (vedi scripts/analysis/rebuild_history.DERIBIT_INSTR):
# inverse USD perp, storia lunga, entro ~3 bps dal lineare USDC su cui eseguiamo.
DERIBIT_SYMBOL = {"BTC": "BTC/USD:BTC", "ETH": "ETH/USD:ETH"}
SCHEMA = ["timestamp", "open", "high", "low", "close", "volume"]


def _fetch_recent_5m(symbol: str, lookback_days: int) -> pd.DataFrame:
    """Coda recente di 5m da Deribit pubblico (ccxt). Paginazione in avanti. Solo letture pubbliche."""
    import ccxt
    ex = ccxt.deribit({"enableRateLimit": True})
    tf_ms = 5 * 60 * 1000
    since = int((time.time() - lookback_days * 86400) * 1000)
    rows: dict[int, list] = {}
    guard = 0
    while guard < 200:
        guard += 1
        try:
            r = ex.fetch_ohlcv(symbol, "5m", since=since, limit=1000)
        except Exception:
            break
        r = [x for x in r if int(x[0]) >= since]
        if not r:
            break
        for x in r:
            t = int(x[0])
            rows[t] = [t, float(x[1]), float(x[2]), float(x[3]), float(x[4]), float(x[5] or 0)]
        nxt = int(r[-1][0]) + tf_ms
        if nxt <= since:
            break
        since = nxt
    if not rows:
        return pd.DataFrame(columns=SCHEMA)
    return pd.DataFrame(rows.values(), columns=SCHEMA).sort_values("timestamp").reset_index(drop=True)


def merge_tail(base: pd.DataFrame, tail: pd.DataFrame) -> pd.DataFrame:
    """Fonde la coda fresca sul feed certificato: concat, dedup per timestamp (la coda VINCE sui
    duplicati, ma le barre certificate storiche restano), riordina. Mantiene lo schema di load_data
    (inclusa 'datetime' se presente). PURA, testabile senza rete."""
    if tail is None or tail.empty:
        return base
    cols = [c for c in SCHEMA if c in base.columns]
    t = tail[[c for c in SCHEMA if c in tail.columns]].copy()
    merged = pd.concat([base[cols], t], ignore_index=True)
    merged = merged.drop_duplicates("timestamp", keep="last").sort_values("timestamp").reset_index(drop=True)
    # ricostruisci 'datetime' coerente (build_frames non la usa, ma load_data la espone)
    merged["datetime"] = pd.to_datetime(merged["timestamp"], unit="ms", utc=True)
    return merged


def fresh_5m(asset: str, lookback_days: int = 12) -> pd.DataFrame:
    """Feed 5m certificato + coda recente effimera (in-memory). Fallback al certificato su errore."""
    base = load_data(asset, "5m")
    sym = DERIBIT_SYMBOL.get(asset)
    if sym is None:
        return base
    try:
        tail = _fetch_recent_5m(sym, lookback_days)
    except Exception:
        return base
    return merge_tail(base, tail)
