"""Phase 2: MDD-reduction focused tuning to push SQS over 85.

SQS bottleneck is risk component (51.2/100) because MDD=9.78%≈10% boundary.
Dropping MDD below 9% would lift SQS risk score significantly.
"""
import json
import subprocess
import shutil
import sys
from pathlib import Path

BASE = "configs/experiments/return_max_long_v8.11_composed_gld_tqqq_bmc30_cl65_vol40_rmin1_cap96.json"
SWEEP_DIR = Path("configs/experiments/_tune_v811_mdd")
SWEEP_DIR.mkdir(exist_ok=True)
SNAPSHOT = "pead_dualconv_ftb_fix_v2_probe"


def make(name: str, signal_ov=None, risk_ov=None, exec_ov=None, sleeves=None) -> str:
    with open(BASE) as f:
        cfg = json.load(f)
    cfg["experiment_name"] = name
    if signal_ov:
        cfg["overrides"]["signal"].update(signal_ov)
    if risk_ov:
        cfg["overrides"]["risk"].update(risk_ov)
    if exec_ov:
        cfg["overrides"]["execution"].update(exec_ov)
    if sleeves:
        cfg["overrides"].update(sleeves)
    path = SWEEP_DIR / f"{name}.json"
    path.write_text(json.dumps(cfg, indent=2))
    return str(path)


def run(config_path: str) -> dict:
    cmd = ["python3", "-m", "apps.backtester.run", "--manifest", config_path,
           "--start", "2022-01-01", "--split", "all", "--initial-equity", "10000",
           "--snapshot-id", SNAPSHOT]
    cache = Path(f"data/parquet/{SNAPSHOT}/.runtime_cache")
    if cache.exists():
        shutil.rmtree(cache)
    proc = subprocess.run(cmd, capture_output=True, text=True, timeout=200)
    tail = proc.stdout.split("\n")[-12:]
    run_id = ret = sqs = trades = None
    for line in tail:
        if "Run complete:" in line:
            run_id = line.split("Run complete:")[1].strip()
        elif "Total return:" in line:
            try: ret = float(line.split(":")[1].strip().rstrip("%"))
            except: pass
        elif "SQS:" in line:
            try: sqs = float(line.split("SQS:")[1].strip().split(" ")[0])
            except: pass
        elif "Trades:" in line:
            try: trades = int(line.split(":")[1].strip())
            except: pass
    mdd = sharpe = pf = None
    if run_id:
        m_path = Path(f"runs/{run_id}/metrics/metrics_summary.json")
        if m_path.exists():
            m = json.loads(m_path.read_text())
            mdd, sharpe, pf = m["max_drawdown_pct"], m["sharpe_ratio"], m["profit_factor"]
    return {"return": ret, "trades": trades, "mdd": mdd, "sharpe": sharpe, "pf": pf, "sqs": sqs, "run_id": run_id}


def main():
    sweeps_arg = sys.argv[1] if len(sys.argv) > 1 else "all"

    SWEEPS = [
        # Position sizing reduction (baseline 0.96)
        ("M01_pos80", None, {"max_position_value_pct": 0.80}, None, None),
        ("M02_pos70", None, {"max_position_value_pct": 0.70}, None, None),
        # Per-trade risk reduction (baseline 0.65)
        ("M03_ptr55", None, {"per_trade_risk_pct": 0.55, "per_trade_risk_pct_a_tier": 0.6}, None, None),
        ("M04_ptr50", None, {"per_trade_risk_pct": 0.50, "per_trade_risk_pct_a_tier": 0.55}, None, None),
        # Combined: pos↓ + risk↓
        ("M05_pos80_ptr55", None, {"max_position_value_pct": 0.80, "per_trade_risk_pct": 0.55, "per_trade_risk_pct_a_tier": 0.6}, None, None),
        # Stop ATR tighter (baseline 3) - catches losers earlier
        ("M06_stop25", None, {"stop_atr_multiplier": 2.5}, None, None),
        # Re-enable macro risk-off scaler
        ("M07_ro_07", None, {"macro_regime_risk_off_size_scaler": 0.7}, None, None),
        ("M08_ro_05", None, {"macro_regime_risk_off_size_scaler": 0.5}, None, None),
        # Defensive parking variants
        ("M09_park_calm", None, {"cash_parking_preset": "qqqm_low_dd_tqqq_calm_v2_gld"}, None, None),
        ("M10_park_conserv", None, {"cash_parking_preset": "qqqm_low_dd_tqqq_conservative_gld_brake_v2"}, None, None),
        ("M11_park_brake_v3", None, {"cash_parking_preset": "qqqm_low_dd_tqqq_active_v2_gld_brake_v3"}, None, None),
        # Defensive risk_off sleeves
        ("M12_ro_balanced", None, None, None, {"risk_off_alpha_sleeve_preset": "risk_off_alpha_gld_crisis65_balanced_refined"}),
        ("M13_ro_crisis60", None, None, None, {"risk_off_alpha_sleeve_preset": "risk_off_alpha_gld_crisis60"}),
        # Combos: best defensive + position cut
        ("M20_combo1", None, {"max_position_value_pct": 0.80, "macro_regime_risk_off_size_scaler": 0.6}, None, None),
        ("M21_combo2", None, {"max_position_value_pct": 0.80, "per_trade_risk_pct": 0.55, "per_trade_risk_pct_a_tier": 0.6, "macro_regime_risk_off_size_scaler": 0.6}, None, None),
    ]

    if sweeps_arg != "all":
        idx = [int(x) for x in sweeps_arg.split(",")]
        SWEEPS = [SWEEPS[i] for i in idx]

    baseline = {"return": 6839, "mdd": 9.78, "sharpe": 3.53, "pf": 8.26, "sqs": 84.8, "trades": 329}
    print(f"BASELINE v8.11: ret={baseline['return']}% MDD={baseline['mdd']}% Sharpe={baseline['sharpe']} PF={baseline['pf']} SQS={baseline['sqs']} trades={baseline['trades']}", flush=True)
    print("=" * 130, flush=True)
    results = []
    for name, sig_ov, risk_ov, exec_ov, sleeves in SWEEPS:
        path = make(name, sig_ov, risk_ov, exec_ov, sleeves)
        params = {k: v for d in (sig_ov, risk_ov, exec_ov, sleeves) if d for k, v in d.items()}
        print(f"\n>>> {name}: {params}", flush=True)
        try:
            r = run(path)
            r["name"] = name
            if r["return"] is None:
                print(f"    FAILED", flush=True); continue
            d_ret = r["return"] - baseline["return"]
            d_sqs = (r["sqs"] or 0) - baseline["sqs"]
            d_mdd = (r["mdd"] or 0) - baseline["mdd"]
            print(f"    ret={r['return']:.0f}% (Δ{d_ret:+.0f}) MDD={r['mdd']:.2f}% (Δ{d_mdd:+.2f}) Sharpe={r['sharpe']:.2f} PF={r['pf']:.2f} SQS={r['sqs']:.1f} (Δ{d_sqs:+.1f}) trades={r['trades']}", flush=True)
            results.append(r)
        except Exception as e:
            print(f"    FAILED: {e}", flush=True)

    print("\n" + "=" * 130, flush=True)
    print("SUMMARY (sorted by SQS, then return):", flush=True)
    results.sort(key=lambda x: (x.get("sqs") or 0, x.get("return") or 0), reverse=True)
    print(f"{'name':20s} {'return':>10s} {'MDD':>8s} {'Sharpe':>8s} {'PF':>6s} {'SQS':>7s} {'trades':>7s}", flush=True)
    print(f"{'BASELINE':20s} {baseline['return']:>9.0f}% {baseline['mdd']:>7.2f}% {baseline['sharpe']:>8.2f} {baseline['pf']:>6.2f} {baseline['sqs']:>7.1f} {baseline['trades']:>7d}", flush=True)
    for r in results:
        print(f"{r['name']:20s} {r['return']:>9.0f}% {r['mdd']:>7.2f}% {r['sharpe']:>8.2f} {r['pf']:>6.2f} {r['sqs']:>7.1f} {r['trades']:>7d}", flush=True)


if __name__ == "__main__":
    main()
