#!/usr/bin/env python3
"""
Score Theta Parquet rows with a trained :func:`~RenTech.strategy_stack.train_vol_mispricing_xgb`
model (``.joblib`` from training). Writes CSV with ``pred_vrp_edge`` = predicted ``rv_fwd - IV``.

Example::

    python RenTech/strategy_stack/predict_vol_mispricing_xgb.py \\
      --artifact RenTech/data/models/vol_mispricing_xgb.joblib \\
      --parquet RenTech/data/theta_chunks/spy_1545_2024_01_ivfilled.parquet \\
      --out /tmp/scored_2024_01.csv
"""

from __future__ import annotations

import argparse
import sys
from pathlib import Path

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

import joblib
import pandas as pd

from RenTech.core.theta_chunks_loader import _session_dates_series
from RenTech.strategy_stack.train_vol_mispricing_xgb import FEATURE_COLUMNS, featurize_dataframe
from RenTech.strategy_stack.vrp_backtester import load_spy_vix_from_yfinance, normalize_spy_df


def main() -> None:
    ap = argparse.ArgumentParser(description="Score options with vol-mispricing XGBoost model")
    ap.add_argument(
        "--artifact",
        type=Path,
        required=True,
        help="Path to vol_mispricing_xgb.joblib from training",
    )
    ap.add_argument(
        "--parquet",
        type=Path,
        required=True,
        help="One monthly spy_1545_*.parquet or *_ivfilled.parquet",
    )
    ap.add_argument("--out", type=Path, required=True, help="Output CSV path")
    ap.add_argument(
        "--max-rows",
        type=int,
        default=0,
        help="After featurizing, cap rows scored (0 = all)",
    )
    args = ap.parse_args()

    art = args.artifact.expanduser()
    if not art.is_file():
        print(f"ERROR: not a file: {art}", file=sys.stderr)
        sys.exit(1)

    pq = args.parquet.expanduser()
    if not pq.is_file():
        print(f"ERROR: not a file: {pq}", file=sys.stderr)
        sys.exit(1)

    bundle = joblib.load(art)
    model = bundle["model"]
    cols = list(bundle.get("feature_columns", FEATURE_COLUMNS))
    if cols != FEATURE_COLUMNS:
        print("WARN: artifact feature_columns differ from current script; using artifact columns.", file=sys.stderr)

    df = pd.read_parquet(pq)
    if df.empty:
        print("ERROR: empty parquet", file=sys.stderr)
        sys.exit(1)

    ts0 = pd.read_parquet(pq, columns=["quote_datetime"])
    q_min = _session_dates_series(ts0["quote_datetime"]).min()
    q_max = _session_dates_series(ts0["quote_datetime"]).max()
    yf_start = (pd.Timestamp(q_min) - pd.Timedelta(days=400)).strftime("%Y-%m-%d")
    yf_end = (pd.Timestamp(q_max) + pd.Timedelta(days=14)).strftime("%Y-%m-%d")
    spy_df = normalize_spy_df(load_spy_vix_from_yfinance(yf_start, yf_end))

    feat = featurize_dataframe(df, spy_df)
    if feat.empty:
        print("ERROR: no rows passed featurization filters", file=sys.stderr)
        sys.exit(1)

    if args.max_rows > 0:
        feat = feat.head(int(args.max_rows))

    X = feat[cols].astype("float64")
    pred = model.predict(X)

    out = df.iloc[feat["_row"].astype(int)].copy()
    out["pred_vrp_edge"] = pred
    out.to_csv(args.out, index=False)
    print(f"Wrote {len(out)} rows to {args.out}")


if __name__ == "__main__":
    main()
