"""
Sequential random vs optuna comparison runner.

Runs each combo twice: once with --search random, once with --search optuna,
so results can be compared apples-to-apples in the sweep DB.

Usage:
    # BTC 1D only: 45 min random then 45 min optuna
    python3 run_comparison.py --hours 0.75 --assets COINBASE_BTCUSD --tfs 1D

    # All BTC timeframes: 30 min each mode per TF
    python3 run_comparison.py --hours 0.5 --assets COINBASE_BTCUSD

    # Full 20-combo comparison: 30 min each mode per combo (20h total)
    python3 run_comparison.py --hours 0.5

    # Alt coins only
    python3 run_comparison.py --hours 0.5 --assets COINBASE_ETHUSD BINANCE_SOLUSD BINANCE_LINKUSD
"""

import subprocess
import sys
import argparse
import time
from datetime import datetime, timedelta

ALL_ASSETS = [
    "COINBASE_BTCUSD",
    "COINBASE_ETHUSD",
    "BINANCE_SOLUSD",
    "BINANCE_LINKUSD",
]
TIMEFRAMES = ["4H", "6H", "8H", "12H", "1D"]
_TF_TO_MIN = {"4H": "240", "6H": "360", "8H": "480", "12H": "720", "1D": "1D"}

EXAMPLES = """
examples:
  python3 run_comparison.py --hours 0.75 --assets COINBASE_BTCUSD --tfs 1D
      BTC 1D: 45 min random then 45 min optuna (1.5h total)

  python3 run_comparison.py --hours 0.5 --assets COINBASE_BTCUSD
      BTC all 5 TFs: 30 min each mode = 5h total

  python3 run_comparison.py --hours 0.5
      All 20 combos both modes: 20h total

  python3 run_comparison.py --hours 1.0 --tfs 1D 12H
      All 4 assets × 2 TFs × 2 modes = 16h total
"""


def run_one(asset, tf, data_path, search, hours):
    label = f"{asset}-{tf} [{search}]"
    print(f"\n{'='*60}")
    print(f"  {label}  ({hours:.2f}h)")
    print(f"  Started: {datetime.now().strftime('%H:%M:%S')}")
    print(f"{'='*60}")

    cmd = [sys.executable, "tools/auto_optimize_loop.py",
           "--data", data_path, "--search", search, "--hours", str(hours)]
    start = time.time()
    result = subprocess.run(cmd)
    elapsed = time.time() - start

    status = "OK" if result.returncode == 0 else f"EXIT {result.returncode}"
    print(f"\n  {label} finished in {elapsed/60:.1f}m  [{status}]")
    return result.returncode


def main():
    parser = argparse.ArgumentParser(
        description="Run random vs optuna comparison on selected assets/timeframes.",
        epilog=EXAMPLES,
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )
    parser.add_argument("--hours", type=float, default=0.75,
                        help="Hours per (combo × mode). Default: 0.75 (45 min).")
    parser.add_argument("--assets", nargs="*", default=None, metavar="ASSET",
                        help="Assets to run (default: all 4). "
                             "E.g. --assets COINBASE_BTCUSD COINBASE_ETHUSD")
    parser.add_argument("--tfs", nargs="*", default=None, metavar="TF",
                        help="Timeframes to run (default: all 5). "
                             "E.g. --tfs 1D 12H")
    parser.add_argument("--modes", nargs="*", default=["random", "optuna"],
                        choices=["random", "optuna"], metavar="MODE",
                        help="Modes to run (default: random optuna). "
                             "E.g. --modes optuna  (to skip random if already done)")
    args = parser.parse_args()

    assets = args.assets if args.assets else ALL_ASSETS
    tfs = args.tfs if args.tfs else TIMEFRAMES
    combos = [(asset, tf, f"data/mlp/{asset}, {_TF_TO_MIN.get(tf, tf)}.csv") for asset in assets for tf in tfs]

    total_runs = len(combos) * len(args.modes)
    total_hours = total_runs * args.hours
    eta = datetime.now() + timedelta(hours=total_hours)

    print(f"Comparison run: {len(combos)} combo(s) × {len(args.modes)} mode(s) = {total_runs} runs")
    print(f"  Modes:     {', '.join(args.modes)}")
    print(f"  Assets:    {', '.join(assets)}")
    print(f"  Timeframes:{', '.join(tfs)}")
    print(f"  Per run:   {args.hours:.2f}h ({args.hours*60:.0f} min)")
    print(f"  Total:     ~{total_hours:.1f}h")
    print(f"  ETA:       {eta.strftime('%Y-%m-%d %H:%M:%S')}")
    print(f"  Started:   {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")

    run_num = 0
    for asset, tf, data_path in combos:
        for search in args.modes:
            run_num += 1
            print(f"\n[{run_num}/{total_runs}]", end="")
            run_one(asset, tf, data_path, search, args.hours)

            remaining = total_runs - run_num
            if remaining > 0:
                eta = datetime.now() + timedelta(hours=remaining * args.hours)
                print(f"  Remaining: {remaining} runs, ETA {eta.strftime('%H:%M:%S')}")

    print(f"\n{'='*60}")
    print(f"All done. Finished at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")


if __name__ == "__main__":
    main()
