#!/usr/bin/env python3
"""
Sweep **best-of-best** concentration: top 10 / 15 / 20 / 25 / 30 / 40 / 50 vs quintile baseline.

Example::

    cd /Users/robzingale/trading_bot
    PYTHONUNBUFFERED=1 .venv/bin/python \\
        RenTech/strategy_stack/run_sp500_momentum_concentration_sweep.py \\
        --start 2016-01-04 --end 2026-04-02 --reuse-equity-cache
"""

from __future__ import annotations

import argparse
import json
import sys
from dataclasses import asdict
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.strategy_stack.run_sp500_dip_standard import _filter_equity_by_history
from RenTech.strategy_stack.sp500_momentum_backtest import load_equity_panel, run_backtest
from RenTech.strategy_stack.sp500_momentum_index import Sp500MomentumConfig, best_of_best_defaults

LOGS = _REPO / "RenTech" / "data" / "logs"
DEFAULT_OUT = LOGS / "sp500_momentum_concentration_sweep"


def main() -> None:
    ap = argparse.ArgumentParser(description=__doc__.split("\n\n")[0])
    ap.add_argument("--start", default="2016-01-04")
    ap.add_argument("--end", default="2026-04-02")
    ap.add_argument("--yahoo-period", default="max")
    ap.add_argument("--capital", type=float, default=100_000.0)
    ap.add_argument("--reuse-equity-cache", action="store_true")
    ap.add_argument("--out-prefix", type=Path, default=DEFAULT_OUT)
    args = ap.parse_args()

    min_first = pd.Timestamp(args.start).normalize() - pd.Timedelta(days=400)
    equity_dict = load_equity_panel(
        yahoo_period=args.yahoo_period,
        start=args.start,
        end=args.end,
        max_tickers=0,
        refresh_cache=not args.reuse_equity_cache,
        pit_universe=True,
    )
    equity_dict = _filter_equity_by_history(equity_dict, min_first)
    print(f"Universe: {len(equity_dict)} names\n", flush=True)

    base = asdict(Sp500MomentumConfig())
    variants: list[tuple[str, Sp500MomentumConfig]] = [
        ("00_quintile_baseline", Sp500MomentumConfig(**base)),
    ]
    for k in (10, 15, 20, 25, 30, 40, 50):
        patch = best_of_best_defaults(top_n=k)
        variants.append((f"bob_top{k:02d}", Sp500MomentumConfig(**{**base, **patch})))

    results: list[dict] = []
    for name, cfg in variants:
        print(f"=== {name} ===", flush=True)
        _r, _rebal, meta = run_backtest(
            equity_dict=equity_dict,
            cfg=cfg,
            start=args.start,
            end=args.end,
            yahoo_period=args.yahoo_period,
            capital=float(args.capital),
            refresh_shares=False,
            pit_universe=True,
        )
        row = {
            "variant": name,
            "top_n": cfg.top_n,
            "filters": cfg.selection_filters,
            **{k: meta[k] for k in (
                "total_return_pct", "cagr_pct", "sharpe_daily",
                "max_drawdown_pct", "beta_vs_spy", "corr_vs_spy_daily",
            )},
        }
        results.append(row)
        print(
            f"  → return {row['total_return_pct']:+.1f}%  CAGR {row['cagr_pct']:+.1f}%  "
            f"Sharpe {row['sharpe_daily']:.2f}  maxDD {row['max_drawdown_pct']:.1f}%\n",
            flush=True,
        )

    prefix = args.out_prefix.expanduser().resolve()
    prefix.parent.mkdir(parents=True, exist_ok=True)
    df = pd.DataFrame(results).sort_values("total_return_pct", ascending=False)
    csv_path = Path(f"{prefix}.csv")
    df.to_csv(csv_path, index=False)
    Path(f"{prefix}.json").write_text(json.dumps(results, indent=2) + "\n", encoding="utf-8")
    print(df.to_string(index=False), flush=True)
    print(f"\nWrote {csv_path}", flush=True)


if __name__ == "__main__":
    main()
