"""Valida il PairsWorker: replay bar-per-bar sui dati storici == backtest pairs_sim?

Come validate_worker_mr01 per MR01: alimenta il PairsWorker con finestre trailing
crescenti (simula il feed live) e confronta trade/capitale finale col backtest di
riferimento scripts/analysis/pairs_research.pairs_sim. Se combaciano, la semantica
live (z-score causale, exit |z|<=z_exit o max_bars, fee 2 gambe) e' fedele.
"""
from __future__ import annotations

import shutil
import sys
import tempfile
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.pairs_worker import PairsWorker
from scripts.analysis.pairs_research import aligned, aligned_ohlc, pairs_sim, pairs_sim_flat
from scripts.strategies.PR01_pairs_reversion import PAIRS

# Config 15m promossa dal gate (gioco Blind Traders + flat-skip): vedi
# docs/diary/2026-06-09-pairs15m-port06-gate.md
CFG_15M = dict(n=66, z_in=1.674, z_exit=1.0, max_bars=35, flat_skip=True)


def replay(a, b, params, data_dir, tf="1h", ohlc=False) -> PairsWorker:
    if ohlc:
        m = aligned_ohlc(a, b, tf)
        df_a = pd.DataFrame({"timestamp": m["timestamp"], "open": m["open_a"],
                             "high": m["high_a"], "low": m["low_a"], "close": m["close_a"]})
        df_b = pd.DataFrame({"timestamp": m["timestamp"], "open": m["open_b"],
                             "high": m["high_b"], "low": m["low_b"], "close": m["close_b"]})
    else:
        m = aligned(a, b, tf)
        df_a = m[["timestamp"]].copy(); df_a["close"] = m["close_a"].values
        df_b = m[["timestamp"]].copy(); df_b["close"] = m["close_b"].values
    w = PairsWorker(a, b, tf, params=params, fee_rt=0.001, data_dir=data_dir)
    w._save_state = lambda: None
    w._log = lambda *a, **k: None
    w._notify = lambda *a, **k: None
    window = max(60, w.n + 6)           # finestra trailing >= n+? : z[i] corretto
    for k in range(w.n + 2, len(m) + 1):
        lo = max(0, k - window)
        w.tick(df_a.iloc[lo:k], df_b.iloc[lo:k])
    return w


def _row(label, w, bt):
    bt_cap = 1000.0 * (1 + bt["ret"] / 100)
    cap_match = abs(w.capital - bt_cap) / bt_cap < 0.02 if bt_cap else False
    trd_match = abs(w.total_trades - bt["trades"]) <= max(2, bt["trades"] * 0.02)
    ok = "OK" if (cap_match and trd_match) else "DIFF"
    ww = w.total_wins / w.total_trades * 100 if w.total_trades else 0
    print(f"  {label:<16s}{w.capital:>13.0f}{w.total_trades:>6d}{ww:>6.1f}  |  "
          f"{bt_cap:>14.0f}{bt['trades']:>6d}{bt['win']:>6.1f}  {ok}")
    return ok == "OK"


def main():
    print("=" * 100)
    print("  VALIDAZIONE PairsWorker — replay live == backtest (fee 0.20% RT/coppia)")
    print("=" * 100)
    print(f"  {'caso':<16s}{'WORKER cap':>13s}{'trd':>6s}{'win%':>6s}  |  "
          f"{'BACKTEST cap':>14s}{'trd':>6s}{'win%':>6s}  match?")
    print("  " + "-" * 92)
    tmp = Path(tempfile.mkdtemp(prefix="pairs_validate_"))
    allok = True
    try:
        # [A] REGRESSIONE 1h (flat_skip=False, close-only) vs pairs_sim
        for a, b, p in [pp for pp in PAIRS if (pp[0], pp[1]) in {("ETH", "BTC"), ("BTC", "LTC")}]:
            w = replay(a, b, p, tmp, tf="1h", ohlc=False)
            allok &= _row(f"{a}/{b} 1h", w, pairs_sim(a, b, **p))
        # [B] NUOVO: 15m flat-skip (OHLC) vs pairs_sim_flat
        w = replay("ETH", "BTC", CFG_15M, tmp, tf="15m", ohlc=True)
        bt = pairs_sim_flat("ETH", "BTC", tf="15m", **CFG_15M)
        allok &= _row("ETH/BTC 15m-flat", w, bt)
    finally:
        shutil.rmtree(tmp, ignore_errors=True)
    print("  " + "-" * 92)
    print("  match = capitale e trade entro 2% del backtest (diff minime = bar finale aperta).")
    print(f"  ESITO COMPLESSIVO: {'TUTTO OK' if allok else 'DIFFERENZE -> INDAGARE'}")


if __name__ == "__main__":
    main()
