#!/usr/bin/env python3
from __future__ import annotations

import argparse
import json
import subprocess
import sys
from pathlib import Path


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(description="Run train/valid/test backtests for multiple manifests.")
    parser.add_argument("--manifest", action="append", required=True, help="Experiment manifest path. Repeat for multiple manifests.")
    parser.add_argument("--snapshot-dir", default="data/datasets/snapshots", help="Snapshot root directory.")
    parser.add_argument("--output-root", required=True, help="Root directory for run artifacts.")
    parser.add_argument("--summary-path", required=True, help="Path to write summary JSON.")
    return parser.parse_args()


def run_split(root: Path, manifest: str, split: str, output_root: Path, snapshot_dir: str) -> dict[str, object]:
    cmd = [
        sys.executable,
        "apps/backtester/run.py",
        "--manifest",
        manifest,
        "--snapshot-dir",
        snapshot_dir,
        "--split",
        split,
        "--output-root",
        str(output_root),
    ]
    result = subprocess.run(
        cmd,
        cwd=root,
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT,
        text=True,
        check=False,
    )
    tail = result.stdout.splitlines()[-5:] if result.stdout else []
    for line in tail:
        print(line)
    if result.returncode != 0:
        raise RuntimeError(f"{Path(manifest).stem} {split} failed:\n{result.stdout}")

    latest = max(output_root.glob("bt_*"), key=lambda path: path.stat().st_mtime)
    summary = json.loads((latest / "metrics" / "metrics_summary.json").read_text())
    return {
        "run_id": latest.name,
        "ret": summary["total_return_pct"],
        "dd": summary["max_drawdown_pct"],
        "n": summary["trade_count"],
        "pf": summary["profit_factor"],
    }


def main() -> None:
    args = parse_args()
    root = Path(__file__).resolve().parents[2]
    output_root = Path(args.output_root)
    output_root.mkdir(parents=True, exist_ok=True)

    rows: list[dict[str, object]] = []
    for manifest in args.manifest:
        exp_name = Path(manifest).stem
        print(f"RUN {exp_name}", flush=True)
        exp_root = output_root / exp_name
        exp_root.mkdir(parents=True, exist_ok=True)
        metrics = {
            split: run_split(root, manifest, split, exp_root, args.snapshot_dir)
            for split in ("train", "valid", "test")
        }
        rows.append({"experiment": exp_name, "metrics": metrics})

    summary_path = Path(args.summary_path)
    summary_path.parent.mkdir(parents=True, exist_ok=True)
    summary_path.write_text(json.dumps(rows, indent=2) + "\n")
    print(f"WROTE {summary_path}")
    for row in rows:
        metrics = row["metrics"]
        print(
            row["experiment"],
            f"tr={metrics['train']['ret']:.2f} v={metrics['valid']['ret']:.2f} t={metrics['test']['ret']:.2f}",
        )


if __name__ == "__main__":
    main()
