"""Gate del CATASTROPHE-CAP auto-finanziato (collar standing) sullo sleeve ETH no-SL.

Tesi: lo sleeve ETH no-SL ha la coda da crash (un long-fade puo' perdere -50/-65% in un
gap). Un COLLAR standing rollato mensilmente — put lunga ~13% OTM finanziata da call corta
~10% OTM — cappa quella coda a premio netto ~zero (validato sui premi REALI di cerbero-bite:
put -13%≈1.0%/m IV55, call +10%≈1.05%/m IV49). Pricing BS calibrato sul reale: skew_put 1.12,
skew_call 1.0. Caveat: il collar aggiunge delta SHORT-ETH con dead-zone -p/+c -> cappa anche
l'upside; nei mesi tranquilli (ETH dentro la banda) costa ~zero. Il gate dice se aiuta netto.

uv run python scripts/analysis/eth_collar_gate.py
"""
from __future__ import annotations
import sys
from pathlib import Path
import numpy as np
import pandas as pd

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

from scripts.analysis.explore_lab import get_df
from scripts.analysis.combine_portfolio import IDX, SPLIT, OOS_DATE, metrics, port_returns, _norm
from scripts.analysis.option_overlay_lab import dvol_for, bs_put, bs_call
from scripts.analysis.mr02eth_port06_gate import (
    gen_donchian_base, build_trades, build_trades_exit16, daily_equity, port_metrics, CAPS)
from src.portfolio.sleeves import all_sleeve_equities

HY = 24 * 365.0


def collar_daily_returns(df, dvol, p_otm=0.13, c_otm=0.10, skew_put=1.12, skew_call=1.0,
                         roll_h=24 * 30) -> pd.Series:
    """Collar standing rollato ogni roll_h ore. Ritorna la SERIE di rendimenti GIORNALIERI
    (frazione del notional collar): MTM = d(intrinseco) - theta (premio netto amortizzato)."""
    c = df["close"].values; ts = pd.to_datetime(df["timestamp"], unit="ms", utc=True)
    n = len(c)
    val = np.zeros(n)          # valore collar (frac notional) marcato a intrinseco - premio residuo
    T = roll_h / HY
    k = 0
    while k < n - 1:
        S0 = c[k]; sig = dvol[k] if not np.isnan(dvol[k]) else 0.6
        Kp = S0 * (1 - p_otm); Kc = S0 * (1 + c_otm)
        prem = bs_put(S0, Kp, T, sig * skew_put) / S0 - bs_call(S0, Kc, T, sig * skew_call) / S0
        end = min(k + roll_h, n - 1)
        span = end - k
        for j in range(k, end + 1):
            intr = (max(Kp - c[j], 0.0) - max(c[j] - Kc, 0.0)) / S0
            frac_elapsed = (j - k) / span if span else 1.0
            val[j] = intr - prem * (1 - frac_elapsed)   # premio pagato up-front, amortizzato a 0 a scadenza
        k = end
    s = pd.Series(val, index=ts)
    daily = s.resample("1D").last().reindex(IDX).ffill().bfill()
    return daily.diff().fillna(0.0)     # rendimento giornaliero (frac notional)


def combine(fade_eq: pd.Series, collar_dr: pd.Series, hedge_frac: float) -> pd.Series:
    """sleeve = fade no-SL + hedge_frac * collar. Combina i rendimenti giornalieri."""
    fr = fade_eq.pct_change().fillna(0.0)
    return _norm((1 + fr + hedge_frac * collar_dr).cumprod())


def crash_audit(df, dvol, p_otm, c_otm, hedge_frac):
    """P&L del collar nei mesi di crollo ETH peggiori (frac notional)."""
    cr = collar_daily_returns(df, dvol, p_otm=p_otm, c_otm=c_otm)
    # ETH daily ret mensile
    cdf = pd.Series(df["close"].values, index=pd.to_datetime(df["timestamp"], unit="ms", utc=True)).resample("1D").last().reindex(IDX).ffill()
    mret = cdf.resample("30D").last().pct_change()
    collar_m = (1 + cr).resample("30D").apply(lambda x: x.prod()) - 1
    worst = mret.nsmallest(5)
    print(f"    {'mese (fine)':>12}{'ETH 30g%':>10}{'collar P&L%':>13}")
    for t, r in worst.items():
        cm = collar_m.reindex([t], method="nearest").iloc[0] * hedge_frac * 100
        print(f"    {str(t.date()):>12}{r*100:>9.0f}%{cm:>12.1f}%")


def main():
    print("=" * 96)
    print(f"  GATE collar standing (catastrophe-cap) sullo sleeve ETH no-SL | OOS da {OOS_DATE}")
    print("=" * 96)
    df = get_df("ETH", "1h"); dvol = dvol_for(df, "ETH")
    eq = dict(all_sleeve_equities())
    ids = [k for k in eq if k in {"MR01_BTC","MR02_BTC","MR07_BTC","MR01_ETH","MR02_ETH","MR07_ETH",
        "DIP01_BTC","TR01_basket","ROT02_rot","PR_ETHBTC","PR_LTCETH","PR_ADAETH","PR_BTCLTC","PR_ETHSOL","TSM01","SH_BTC","SH_ETH"}]
    base_ents = gen_donchian_base(df, n=20, sl_atr=2.0, trend_max=3.0)
    nosl_ents = gen_donchian_base(df, n=20, sl_atr=2.0, trend_max=3.0, use_sl=False)

    def pm(ce):
        m = dict(eq); m["MR02_ETH"] = ce; return port_metrics(m, ids)

    f_l, o_l = pm(daily_equity(build_trades_exit16(base_ents, df, sl_confirm=0.5), df))
    fade_nosl = daily_equity(build_trades(nosl_ents, df), df)
    f0, o0 = pm(fade_nosl)
    print(f"\n  {'sleeve ETH':<30s}{'FULL Sh':>8s}{'FULL DD':>8s}   |{'OOS Sh':>8s}{'OOS DD':>8s}")
    print("  " + "-" * 78)
    print(f"  {'LIVE EXIT-16 (rif)':<30s}{f_l['sharpe']:>8.2f}{f_l['dd']:>8.2f}   |{o_l['sharpe']:>8.2f}{o_l['dd']:>8.2f}")
    print(f"  {'no-SL nudo':<30s}{f0['sharpe']:>8.2f}{f0['dd']:>8.2f}   |{o0['sharpe']:>8.2f}{o0['dd']:>8.2f}")

    configs = [
        ("put13/call10 hf0.45", 0.13, 0.10, 0.45),
        ("put13/call10 hf0.30", 0.13, 0.10, 0.30),
        ("put15/call12 hf0.45", 0.15, 0.12, 0.45),
        ("put20/call15 hf0.45", 0.20, 0.15, 0.45),
        ("put13/call08 hf0.45", 0.13, 0.08, 0.45),
    ]
    rows = []
    for name, p, cc, hf in configs:
        cr = collar_daily_returns(df, dvol, p_otm=p, c_otm=cc)
        ce = combine(fade_nosl, cr, hf)
        f_c, o_c = pm(ce)
        rows.append((name, p, cc, hf, f_c, o_c))
        print(f"  {'no-SL + '+name:<30s}{f_c['sharpe']:>8.2f}{f_c['dd']:>8.2f}   |{o_c['sharpe']:>8.2f}{o_c['dd']:>8.2f}")

    print("\n  " + "=" * 90)
    print(f"  vs LIVE EXIT-16 (FULL {f_l['sharpe']:.2f}/{f_l['dd']:.2f} OOS {o_l['sharpe']:.2f}/{o_l['dd']:.2f}) e vs no-SL")
    print("  " + "-" * 90)
    for name, p, cc, hf, f_c, o_c in rows:
        print(f"  {name:<22s} Δ vsEXIT16 FULL {f_c['sharpe']-f_l['sharpe']:+.2f}/{f_c['dd']-f_l['dd']:+.2f} "
              f"OOS {o_c['sharpe']-o_l['sharpe']:+.2f}/{o_c['dd']-o_l['dd']:+.2f}  | "
              f"Δ vsNoSL DD {f_c['dd']-f0['dd']:+.2f}")

    print("\n  --- audit crash: P&L collar (hf-scaled) nei 5 mesi ETH peggiori (put13/call10 hf0.45) ---")
    crash_audit(df, dvol, 0.13, 0.10, 0.45)


if __name__ == "__main__":
    main()
