#!/usr/bin/env python3
"""
Tier A benchmark: **Yahoo Finance** index/ETN/ETF series + **documented synthetics** where no index
exists (see :mod:`RenTech.strategy_stack.tier_a_series`).

Usage::

    python RenTech/strategy_stack/tier_a_index_benchmark.py --start 2008-01-01 --end 2024-01-01
    python RenTech/strategy_stack/tier_a_index_benchmark.py --exclude-optional-etf --output-csv /tmp/tier_a.csv

``--exclude-optional-etf`` drops PUTW/PBP so the sample starts in **2008** (longer history) at
the cost of omitting PUTW-based rows. SPYC is not in the default join (2020 inception collapses n).
"""

from __future__ import annotations

import argparse
import csv
import math
import sys
from pathlib import Path

_REPO_ROOT = Path(__file__).resolve().parents[2]
if str(_REPO_ROOT) not in sys.path:
    sys.path.insert(0, str(_REPO_ROOT))

from RenTech.strategy_stack.tier_a_series import (
    build_return_panel,
    summarize_strategy,
)

ROW_LABELS: dict[str, tuple[str, str]] = {
    "sp500_tr": ("S&P 500 TR (^SP500TR)", "benchmark"),
    "spy_price": ("SPY price return", "benchmark"),
    "shv_cash": ("SHV cash / T-Bill proxy", "cash"),
    "bxm": ("BXM buy-write index", "12–20 / listed"),
    "putw_etf": ("PUTW put-write ETF (CBOE PUT proxy)", "12–20"),
    "pbp": ("PBP buy-write ETF", "12–20"),
    "vixy": ("VIXY long VIX futures", "<12 / tail"),
    "svxy": ("SVXY short VIX futures", "12–20 (risk: 2018)"),
    "uvxy": ("UVXY long vol levered", ">30"),
    "syn_vrp_carry": ("Synthetic: VRP variance carry", "cross"),
    "syn_straddle_complacency": ("Synthetic: straddle toy if VIX<12", "<12"),
    "syn_vxth_style": ("Synthetic: VXTH-style VIXY weight", "<12"),
    "syn_short_vol_normal": ("Synthetic: 12% SVXY in 12–20", "12–20"),
    "syn_long_uvxy_panic": ("Synthetic: 10% UVXY if VIX>30", ">30"),
    "syn_iron_condor_blend": ("Synthetic: BXM/SHV IC proxy", "12–20"),
    "syn_jade_lizard_blend": ("Synthetic: 50% PUTW + 50% BXM", "12–20"),
    "syn_zero_dte_vrp": ("Synthetic: 0DTE-style VRP toy", "12–20"),
    "syn_calendar_vvix": ("Synthetic: VIXY tilt vs ^VVIX", "20–30"),
}


def main() -> None:
    ap = argparse.ArgumentParser(description="Tier A index + synthetic strategy benchmark (Yahoo).")
    ap.add_argument("--start", type=str, default="2008-01-01")
    ap.add_argument("--end", type=str, default="2024-01-01")
    ap.add_argument(
        "--exclude-optional-etf",
        action="store_true",
        help="Drop PUTW/PBP/SPYC for longest common history (omit PUTW-dependent rows).",
    )
    ap.add_argument("--output-csv", type=Path, default=None)
    args = ap.parse_args()

    panel, vix_lvl, warns = build_return_panel(
        args.start,
        args.end,
        exclude_optional=bool(args.exclude_optional_etf),
    )
    if panel.empty:
        print("ERROR: empty return panel (check Yahoo / date range).", file=sys.stderr)
        for k, v in warns.items():
            print(f"  warn {k}: {v}", file=sys.stderr)
        sys.exit(1)

    rf = panel["shv_cash"]

    rows: list[dict[str, object]] = []
    for col in panel.columns:
        label, theme = ROW_LABELS.get(col, (col, ""))
        s = summarize_strategy(panel[col], vix_lvl, rf_daily=rf)
        rows.append(
            {
                "id": col,
                "label": label,
                "theme": theme,
                **s,
            }
        )

    rows.sort(key=lambda r: (-float(r["cagr"]) if isinstance(r["cagr"], float) and math.isfinite(r["cagr"]) else -999.0))

    print("=" * 120)
    print(f" Tier A benchmark | Yahoo Finance + documented synthetics | {args.start} → {args.end} | n={panel.shape[0]} days")
    if warns:
        print(" Warnings:")
        for k, v in sorted(warns.items()):
            print(f"   - {k}: {v}")
    print("=" * 120)
    hdr = (
        f"{'id':<24} {'CAGR':>8} {'totRet':>9} {'maxDD':>8} {'annVol':>8} {'Sharpe':>7} "
        f"{'<12':>8} {'12-20':>8} {'20-30':>8} {'>30':>8}"
    )
    print(hdr)
    print("-" * len(hdr))
    for r in rows:
        cg = r["cagr"]
        tr = r["total_return"]
        cg_s = f"{float(cg):.2%}" if isinstance(cg, float) and math.isfinite(cg) else "n/a"
        tr_s = f"{float(tr):.2%}" if isinstance(tr, float) and math.isfinite(tr) else "n/a"
        dd = r["max_drawdown"]
        vo = r["ann_vol"]
        sh = r["sharpe"]
        dd_s = f"{float(dd):.2%}" if isinstance(dd, float) and math.isfinite(dd) else "n/a"
        vo_s = f"{float(vo):.2%}" if isinstance(vo, float) and math.isfinite(vo) else "n/a"
        sh_s = f"{float(sh):.2f}" if isinstance(sh, float) and math.isfinite(sh) else "n/a"

        def _ms(x: object) -> str:
            if not isinstance(x, float) or not math.isfinite(x):
                return "n/a"
            return f"{x * 252.0:.2%}"

        print(
            f"{str(r['id']):<24} {cg_s:>8} {tr_s:>9} {dd_s:>8} {vo_s:>8} {sh_s:>7} "
            f"{_ms(r['mean_daily_lt12']):>8} {_ms(r['mean_daily_12_20']):>8} "
            f"{_ms(r['mean_daily_20_30']):>8} {_ms(r['mean_daily_gt30']):>8}"
        )
    print("-" * len(hdr))
    print("Mean columns: annualized mean daily return in each VIX bucket (×252), same-day VIX label.")
    print("Synthetics are **not** investable marks — see tier_a_series.py docstrings.")
    print("=" * 120)

    if args.output_csv is not None:
        p = args.output_csv.expanduser()
        p.parent.mkdir(parents=True, exist_ok=True)
        keys = list(rows[0].keys()) if rows else []
        with p.open("w", newline="", encoding="utf-8") as f:
            w = csv.DictWriter(f, fieldnames=keys)
            w.writeheader()
            for r in rows:
                w.writerow(r)
        print(f"Wrote {p}")


if __name__ == "__main__":
    main()
