#!/usr/bin/env python3
"""DeepEval Phase 1: Run WFV comparison matrix (clean lineage).

Usage:
    python -m apps.tools.run_deepeval_phase1 [--output-root runs/deepeval_phase1]

Runs walk-forward validation for:
  1.1 Clean lineage baseline
  1.2 Clean lineage replay of legacy v0.326

Then prints a comparison matrix.
"""
from __future__ import annotations

import argparse
import json
import subprocess
import sys
from pathlib import Path
from concurrent.futures import ProcessPoolExecutor, as_completed


CONFIGS = {
    "v1.1_clean_baseline": "configs/experiments/return_max_long_v1.1.json",
    "v1.2_clean_replay": "configs/experiments/return_max_long_v1.2.json",
}

WF_TRAIN_DAYS = 504
WF_TEST_DAYS = 63


def run_single_wfv(label: str, manifest_path: str, output_root: str) -> dict:
    """Run a single WFV and return the summary dict."""
    out_dir = str(Path(output_root) / label)
    cmd = [
        sys.executable, "-m", "apps.backtester.run",
        "--manifest", manifest_path,
        "--walk-forward",
        "--wf-train-days", str(WF_TRAIN_DAYS),
        "--wf-test-days", str(WF_TEST_DAYS),
        "--output-root", out_dir,
        "--initial-equity", "100000",
        "--snapshot-dir", "data/datasets/snapshots",
    ]
    print(f"[{label}] Starting WFV...")
    result = subprocess.run(cmd, capture_output=True, text=True)
    if result.returncode != 0:
        print(f"[{label}] FAILED:\n{result.stderr[-500:]}")
        return {"label": label, "error": result.stderr[-500:]}

    summary_path = Path(out_dir) / "walk_forward" / "walk_forward_summary.json"
    if not summary_path.exists():
        print(f"[{label}] WARNING: summary not found at {summary_path}")
        return {"label": label, "error": "summary not found"}

    with open(summary_path) as f:
        summary = json.load(f)
    print(f"[{label}] Done. Test mean return: {summary['test_aggregate']['mean_return_pct']:.1f}%")
    return {"label": label, "summary": summary}


def print_comparison_matrix(results: list[dict]) -> None:
    """Print a formatted comparison matrix."""
    print("\n" + "=" * 90)
    print("DeepEval Phase 1 — WFV Comparison Matrix")
    print("=" * 90)

    header = f"{'Config':<25} {'Test Mean%':>10} {'Test Med%':>10} {'Test Worst%':>11} {'Train-Test Gap':>14} {'Test Sharpe':>11}"
    print(header)
    print("-" * 90)

    for r in results:
        label = r["label"]
        if "error" in r:
            print(f"{label:<25} {'ERROR':>10}")
            continue
        s = r["summary"]
        ta = s["test_aggregate"]
        gap = s["gap_stats"]
        print(
            f"{label:<25} "
            f"{ta['mean_return_pct']:>10.1f} "
            f"{ta['median_return_pct']:>10.1f} "
            f"{ta['worst_return_pct']:>11.1f} "
            f"{gap['mean_train_test_return_gap_pct']:>14.1f} "
            f"{ta.get('mean_profit_factor', 0):>11.1f}"
        )

    print("=" * 90)
    print("\nKey interpretation:")
    print("  - v1.1 is the clean-lineage baseline")
    print("  - v1.2 is the clean-lineage replay of legacy v0.326 non-exact core")
    print("  - Train-Test Gap: lower is better (less overfitting)")


def main() -> None:
    parser = argparse.ArgumentParser(description="DeepEval Phase 1: WFV Comparison Matrix")
    parser.add_argument("--output-root", default="runs/deepeval_phase1", help="Output directory")
    parser.add_argument("--parallel", type=int, default=2, help="Max parallel WFV runs")
    args = parser.parse_args()

    results = []
    if args.parallel > 1:
        with ProcessPoolExecutor(max_workers=args.parallel) as executor:
            futures = {
                executor.submit(run_single_wfv, label, path, args.output_root): label
                for label, path in CONFIGS.items()
            }
            for future in as_completed(futures):
                results.append(future.result())
    else:
        for label, path in CONFIGS.items():
            results.append(run_single_wfv(label, path, args.output_root))

    # Sort by label for consistent output
    results.sort(key=lambda r: r["label"])
    print_comparison_matrix(results)

    # Save raw results
    out_path = Path(args.output_root) / "phase1_comparison.json"
    out_path.parent.mkdir(parents=True, exist_ok=True)
    with open(out_path, "w") as f:
        json.dump(results, f, indent=2, default=str)
    print(f"\nRaw results saved to {out_path}")


if __name__ == "__main__":
    main()
