"""Smoke LIVE del nuovo percorso 15m: fetch DIRETTO 15m da Cerbero per ETH/BTC +
freschezza + flat-fraction + un tick reale del PairsWorker(flat_skip).

Verifica cio' che il backtest non vede: che Cerbero serva candele 15m fresche per
entrambe le gambe (il runner ora le fetcha dirette, non resamplate dal 1h) e che il
worker 15m le processi senza errori. NON apre ordini reali (l'esecuzione a 2 gambe e'
gia' coperta da live_pairs_smoke.py, indipendente dal timeframe).

    uv run python scripts/analysis/pairs15m_live_smoke.py
"""
from __future__ import annotations

import sys
import shutil
import tempfile
from datetime import datetime, timezone, timedelta
from pathlib import Path

import pandas as pd

PROJECT_ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(PROJECT_ROOT))

from src.live.cerbero_client import CerberoClient
from src.live.multi_runner import INSTRUMENT_MAP
from src.live.pairs_worker import PairsWorker

CFG = {"n": 66, "z_in": 1.674, "z_exit": 1.0, "max_bars": 35, "flat_skip": True}


def fetch15(cli, asset, days=14):
    inst = INSTRUMENT_MAP.get(asset, f"{asset}-PERPETUAL")
    end = datetime.now(timezone.utc)
    start = end - timedelta(days=days)
    candles = cli.get_historical_v2(inst, start.strftime("%Y-%m-%d"),
                                    end.strftime("%Y-%m-%d"), "15m")
    if not candles:
        return inst, None
    df = pd.DataFrame(candles)
    df["timestamp"] = df["timestamp"].astype("int64")
    return inst, df.sort_values("timestamp").reset_index(drop=True)


def main():
    print("=" * 84)
    print("  SMOKE LIVE — ETH/BTC pairs 15m (fetch diretto Cerbero + tick worker flat-skip)")
    print("=" * 84)
    cli = CerberoClient()
    inst_a, da = fetch15(cli, "ETH")
    inst_b, db = fetch15(cli, "BTC")
    ok = True
    for asset, inst, df in [("ETH", inst_a, da), ("BTC", inst_b, db)]:
        if df is None or df.empty:
            print(f"  {asset} ({inst}): NESSUNA candela 15m -> FAIL"); ok = False; continue
        last = pd.to_datetime(df["timestamp"].iloc[-1], unit="ms", utc=True)
        age_min = (datetime.now(timezone.utc) - last).total_seconds() / 60
        flat = ((df["open"] == df["high"]) & (df["high"] == df["low"]) &
                (df["low"] == df["close"])).mean() * 100
        fresh = age_min < 60
        print(f"  {asset} ({inst}): {len(df)} barre 15m | ultima {last:%Y-%m-%d %H:%M} "
              f"({age_min:.0f} min fa, {'FRESCO' if fresh else 'STALE'}) | flat {flat:.1f}%")
        ok &= fresh
    if da is None or db is None:
        print("\n  ESITO: FAIL (feed 15m assente)."); return
    # tick reale del worker 15m
    tmp = Path(tempfile.mkdtemp(prefix="smoke15m_"))
    try:
        w = PairsWorker("ETH", "BTC", "15m", params=CFG, fee_rt=0.001, data_dir=tmp)
        df_a = pd.DataFrame({"timestamp": da["timestamp"], "open": da["open"], "high": da["high"],
                             "low": da["low"], "close": da["close"]})
        df_b = pd.DataFrame({"timestamp": db["timestamp"], "open": db["open"], "high": db["high"],
                             "low": db["low"], "close": db["close"]})
        w.tick(df_a, df_b)
        print(f"\n  Worker 15m flat_skip={w.flat_skip} -> tick OK | {w.status_summary}")
        print(f"  ESITO: {'OK — feed 15m fresco e worker ticca' if ok else 'ATTENZIONE: feed 15m stale/parziale'}")
    finally:
        shutil.rmtree(tmp, ignore_errors=True)


if __name__ == "__main__":
    main()
