#!/usr/bin/env python3
"""
Run literature catalog specs with **stacking**: add 1 contract each session the signal is true;
each leg exits after ``hold`` sessions (see :func:`run_signal_backtest_stack_while_signal`).

Works for any catalog ``sid`` (e.g. put-write **S053–S055**, mild-VIX put verticals **S084–S091**).

Defaults: Theta chunk calendar, ``$100k`` starting equity for the equity curve.

Example::

    cd /Users/robzingale/trading_bot && PYTHONUNBUFFERED=1 .venv/bin/python \\
      RenTech/strategy_stack/run_lit_putwrite_stack_sids.py \\
      --sids S053,S054,S055 --start 2016-01-04 --end 2026-04-02 --capital 100000 \\
      2>&1 | tee RenTech/data/logs/lit_putwrite_stack_run.log

    cd /Users/robzingale/trading_bot && PYTHONUNBUFFERED=1 .venv/bin/python \\
      RenTech/strategy_stack/run_lit_putwrite_stack_sids.py \\
      --sids S084,S085,S086,S087,S088,S089,S090,S091 --start 2016-01-04 --end 2026-04-02 \\
      --capital 100000 2>&1 | tee RenTech/data/logs/mild_vix_put_spread_stack_run.log

    # Export daily equity curves alongside metrics:
    cd /Users/robzingale/trading_bot && PYTHONUNBUFFERED=1 .venv/bin/python \\
      RenTech/strategy_stack/run_lit_putwrite_stack_sids.py \\
      --sids S055 --start 2016-01-04 --end 2026-04-02 --capital 100000 \\
      --out-equity-csv RenTech/data/logs/s055_equity_daily.csv
"""
from __future__ import annotations

import argparse
import sys
from pathlib import Path

import pandas as pd

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

from RenTech.core.theta_chunks_loader import theta_chunks_date_bounds
from RenTech.strategy_stack import research_literature_theta_strategies as L
from RenTech.strategy_stack.literature_search_agent import _compile_signal, _compile_trade
from RenTech.strategy_stack.literature_strategy_catalog import build_catalog_100


def main() -> None:
    ap = argparse.ArgumentParser(description=__doc__)
    ap.add_argument("--theta-dir", type=Path, default=_REPO / "RenTech/data/theta_chunks")
    ap.add_argument("--sids", type=str, default="S053,S054,S055", help="Comma-separated catalog sids")
    ap.add_argument("--start", type=str, default="2016-01-04")
    ap.add_argument("--end", type=str, default="", help="YYYY-MM-DD inclusive; empty = Theta upper bound")
    ap.add_argument("--capital", type=float, default=100_000.0)
    ap.add_argument(
        "--out-equity-csv",
        type=Path,
        default=None,
        help="Write date-indexed CSV with one column per SID (daily equity, $100k base). "
        "Useful for blending with VRP equity curves.",
    )
    args = ap.parse_args()

    sids = [x.strip() for x in str(args.sids).split(",") if x.strip()]
    by_id = {s.sid: s for s in build_catalog_100()}
    for sid in sids:
        if sid not in by_id:
            raise SystemExit(f"Unknown sid {sid!r}")

    end = str(args.end).strip()
    if not end:
        _, d1 = theta_chunks_date_bounds(args.theta_dir.expanduser().resolve())
        end = d1.strftime("%Y-%m-%d")
        print(f"--end omitted → using Theta upper bound {end}", flush=True)

    print(f"Preparing Theta context {args.start}..{end} …", flush=True)
    days, panel, get_chain, iv_atm, skew_put_minus_call_iv, n_contracts, spy_wide = (
        L.prepare_theta_research_context(
            theta_dir=args.theta_dir,
            capital=float(args.capital),
            start=str(args.start),
            end=end,
            max_days=0,
        )
    )
    print(
        f"  sessions={len(days)}  first={days[0].date()}  last={days[-1].date()}  "
        f"capital=${float(args.capital):,.0f}",
        flush=True,
    )

    equity_series: dict[str, pd.Series] = {}
    for sid in sids:
        spec = by_id[sid]
        sig = _compile_signal(spec, panel, iv_atm, skew_put_minus_call_iv, n_contracts, spy_wide)
        tfn = _compile_trade(spec)
        ex, pnls, ntr, mx = L.run_signal_backtest_stack_while_signal(
            days, get_chain, panel, sig, int(spec.hold), tfn, spec.trade_params
        )
        eq, sh = L.equity_curve_from_realized(ex, pnls, days, float(args.capital))
        end_eq = float(eq.iloc[-1])
        tot_pnl = end_eq - float(args.capital)
        tot_ret = (end_eq / float(args.capital) - 1.0) * 100.0
        print(
            f"{sid}  hold={spec.hold}  trades={ntr}  max_open={mx}  Sharpe={sh:.4f}  "
            f"total_pnl=${tot_pnl:,.2f}  total_return={tot_ret:.4f}%  end_equity=${end_eq:,.2f}",
            flush=True,
        )
        equity_series[sid] = eq

    if args.out_equity_csv is not None:
        out_path = args.out_equity_csv.expanduser()
        out_path.parent.mkdir(parents=True, exist_ok=True)
        df_eq = pd.DataFrame(equity_series)
        df_eq.index.name = "date"
        df_eq.to_csv(out_path)
        print(f"Equity CSV → {out_path}", flush=True)


if __name__ == "__main__":
    main()
