"""SKH_R_PCTL final: verify top configs with sk.study + marginal, refine for minFull/DD."""
from __future__ import annotations
import sys
sys.path.insert(0, "/opt/docker/PythagorasGoal/scripts/research/skyhook")
import numpy as np, pandas as pd
import skyhooklib as sk
from src.backtest.harness import backtest_signals
from src.strategies import skyhook as S
from src.strategies.skyhook import SkyhookParams, HTF_MIN

# import the structural builder from the sweep script
import importlib.util
spec = importlib.util.spec_from_file_location(
    "skr", "/opt/docker/PythagorasGoal/scripts/research/skyhook/runs/SKH_R_PCTL.py")
skr = importlib.util.module_from_spec(spec)
# avoid running its __main__
import builtins
_orig_name = "__main__"
spec.loader.exec_module(skr)  # defines functions; __main__ guard prevents the sweep

HOLDOUT = sk.HOLDOUT
FEE = sk.FEE_RT


def study_struct(name, cfg, p):
    """sk.study-equivalent for our structural variant: FULL+HOLD+fee-sweep+per-year BOTH assets."""
    per_asset = {}
    fee_ok_all = True
    for a in ("BTC", "ETH"):
        ltf, htf = sk.frames(a)
        ent = skr.pctl_entries(ltf, htf, p, **cfg)
        m = backtest_signals(ltf, ent, fee_rt=FEE, leverage=1.0, asset=a, tf="230m")
        eq = m.equity
        idx = pd.DatetimeIndex(pd.to_datetime(m.eq_index, utc=True))
        hmask = np.asarray(idx >= HOLDOUT)
        full = dict(sharpe=round(m.sharpe, 3), ret=round(m.net_return, 4), maxdd=round(m.max_dd, 4),
                    n_trades=int(m.n_trades), win_rate=round(m.win_rate, 1))
        hold = skr._split(eq, idx, hmask)
        sweep = {}
        for f in (0.0, 0.001, 0.002, 0.003):
            mf = backtest_signals(ltf, ent, fee_rt=f, leverage=1.0, asset=a, tf="230m")
            sweep[f"{f*100:.2f}%"] = round(mf.sharpe, 3)
        fee_ok_all = fee_ok_all and (sweep["0.30%"] > 0)
        per_asset[a] = dict(full=full, hold=hold, yearly={int(y): round(v, 4) for y, v in m.yearly.items()},
                            fee_sweep=sweep)
    mf = min(per_asset[a]["full"]["sharpe"] for a in per_asset)
    mh = min(per_asset[a]["hold"]["sharpe"] for a in per_asset)
    mt = min(per_asset[a]["full"]["n_trades"] for a in per_asset)
    mdd = max(per_asset[a]["full"]["maxdd"] for a in per_asset)
    grade = "PASS" if (mt >= 20 and mf >= 0.5 and mh >= 0.2 and fee_ok_all) else \
            ("WEAK" if (mt >= 20 and mf >= 0.3 and mh >= 0.0) else "FAIL")
    print(f"\n=== {name} -> {grade}  (minFull={mf:+.2f} minHold={mh:+.2f} minTr={mt} maxDD={mdd*100:.0f}% feeOK={fee_ok_all})")
    for a in per_asset:
        pa = per_asset[a]
        yr = " ".join(f"{y}:{r*100:+.0f}%" for y, r in pa["yearly"].items())
        print(f"  {a}: FULL Sh={pa['full']['sharpe']:+.2f} ret={pa['full']['ret']*100:+.0f}% DD={pa['full']['maxdd']*100:.0f}%"
              f" n={pa['full']['n_trades']} wr={pa['full']['win_rate']:.0f}% | HOLD Sh={pa['hold']['sharpe']:+.2f} ret={pa['hold']['ret']*100:+.0f}%")
        print(f"      fee: " + " ".join(f"{k}={v:+.2f}" for k, v in pa["fee_sweep"].items()))
        print(f"      yr: {yr}")
    return dict(grade=grade, minFull=mf, minHold=mh, minTr=mt, maxDD=mdd, fee_ok=fee_ok_all, per_asset=per_asset)


def marginal_struct(cfg, p):
    import altlib as al
    def daily(a):
        ltf, htf = sk.frames(a)
        ent = skr.pctl_entries(ltf, htf, p, **cfg)
        m = backtest_signals(ltf, ent, fee_rt=FEE, leverage=1.0, asset=a, tf="230m")
        s = pd.Series(m.equity, index=pd.DatetimeIndex(pd.to_datetime(m.eq_index, utc=True)))
        return s.resample("1D").last().ffill().pct_change().dropna()
    sb, se = daily("BTC"), daily("ETH")
    J = pd.concat({"BTC": sb, "ETH": se}, axis=1, join="inner").fillna(0.0)
    cand = 0.5 * J["BTC"] + 0.5 * J["ETH"]
    return al.marginal_vs_tp01(cand)


if __name__ == "__main__":
    p = skr.v1_like_params()

    # Candidate A: best minHold (exp_volaHi_volHi) -- minFull 0.53
    cfgA = dict(vola_win=None, vol_win=None, vola_lo=0.35, vola_hi=0.95, vol_lo=0.40, vol_hi=1.0)
    # Candidate B: best minFull + lower DD (exp_volaLo_vol0) -- minFull 0.70, DD 39%
    cfgB = dict(vola_win=None, vol_win=None, vola_lo=0.0, vola_hi=0.70, vol_lo=0.0, vol_hi=1.0)

    # Refinements to lift minFull on A while keeping hold-out: tighten vola band / add small vol floor
    cfgC = dict(vola_win=None, vol_win=None, vola_lo=0.10, vola_hi=0.80, vol_lo=0.30, vol_hi=1.0)
    # B + modest vol floor to keep DD low but lift hold
    cfgD = dict(vola_win=None, vol_win=None, vola_lo=0.0, vola_hi=0.70, vol_lo=0.30, vol_hi=1.0)

    rA = study_struct("PCTL-A exp_volaHi_volHi", cfgA, p)
    rB = study_struct("PCTL-B exp_volaLo_vol0", cfgB, p)
    rC = study_struct("PCTL-C exp_volaLoMid_volFloor", cfgC, p)
    rD = study_struct("PCTL-D exp_volaLo_volFloor", cfgD, p)

    print("\n\n##### MARGINAL vs TP01 #####")
    for tag, cfg, r in [("A", cfgA, rA), ("B", cfgB, rB), ("C", cfgC, rC), ("D", cfgD, rD)]:
        mg = marginal_struct(cfg, p)
        print(f"[{tag}] grade={r['grade']} minFull={r['minFull']:+.2f} minHold={r['minHold']:+.2f} DD={r['maxDD']*100:.0f}%"
              f" | corr_full={mg.get('corr_full')} upliftHold={mg.get('blends',{}).get('w25',{}).get('uplift_hold')}"
              f" verdict={mg.get('marginal_verdict')} robust_oos={mg.get('robust_oos')}"
              f" insample_edge={mg.get('has_insample_edge')} hedge={mg.get('is_hedge')}"
              f" cleanYr={mg.get('clean_year_uplift')}")
