"""
Batch optimizer: runs auto_optimize_loop.py on all non-BTC crypto assets across all timeframes.

Usage:
    python3 run_alt_crypto.py                          # use auto_optimize_loop.py default (3 iters × 50M)
    python3 run_alt_crypto.py --hours 15               # 15h total ÷ 15 combos = 1h each
    python3 run_alt_crypto.py --hours 6 --tfs 1D 12H   # 6h total ÷ 6 combos (3 assets × 2 TFs) = 1h each
    python3 run_alt_crypto.py --hours 10 --assets COINBASE_ETHUSD BINANCE_SOLUSD
"""

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

ALT_ASSETS = [
    "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_alt_crypto.py --hours 15
      15h total ÷ 15 combos (3 assets × 5 TFs) = 1h each

  python3 run_alt_crypto.py --hours 6 --tfs 1D 12H
      6h total ÷ 6 combos (3 assets × 2 TFs) = 1h each

  python3 run_alt_crypto.py --hours 10 --assets COINBASE_ETHUSD BINANCE_SOLUSD
      10h total ÷ 10 combos (2 assets × 5 TFs) = 1h each

  python3 run_alt_crypto.py --hours 4 --assets BINANCE_SOLUSD --tfs 1D 12H 8H
      4h total ÷ 3 combos = 1.33h each
"""


def main():
    parser = argparse.ArgumentParser(
        description="Batch optimizer for non-BTC crypto assets across all timeframes.",
        epilog=EXAMPLES,
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )
    parser.add_argument("--hours", type=float, default=None,
                        help="Total hour budget divided evenly across all combos. "
                             "E.g. --hours 15 with 15 combos = 1h each.")
    parser.add_argument("--assets", nargs="*", default=None, metavar="ASSET",
                        help="Assets to run (default: all 3 non-BTC). "
                             "E.g. --assets COINBASE_ETHUSD BINANCE_SOLUSD")
    parser.add_argument("--tfs", nargs="*", default=None, metavar="TF",
                        help="Timeframes to run (default: all 5). "
                             "E.g. --tfs 1D 12H 8H")
    parser.add_argument("--search", type=str, default="random", choices=["random", "optuna"],
                        help="Search strategy: 'random' (default) or 'optuna' (biased sampling)")
    args = parser.parse_args()

    assets = [a.upper() for a in args.assets] if args.assets else ALT_ASSETS
    tfs = [tf.upper() for tf in 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 = len(combos)

    if args.hours is not None:
        hours_per_combo = args.hours / total
        eta = datetime.now() + timedelta(hours=args.hours)
        print(f"Total budget: {args.hours}h  ÷  {total} combos = {hours_per_combo:.2f}h each")
        print(f"Assets: {', '.join(assets)}")
        print(f"Timeframes: {', '.join(tfs)}")
        print(f"Estimated completion: {eta.strftime('%Y-%m-%d %H:%M:%S')}")
    else:
        hours_per_combo = None
        print(f"Running {total} combos × default duration each")
        print(f"Assets: {', '.join(assets)}")
        print(f"Timeframes: {', '.join(tfs)}")
    print(f"Started at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")

    for i, (asset, tf, data_path) in enumerate(combos, 1):
        label = f"{asset}-{tf}"
        per_combo_label = f"{hours_per_combo:.2f}h" if hours_per_combo is not None else "default"
        print(f"\n{'='*60}")
        print(f"[{i}/{total}] {label}  ({per_combo_label})")
        print(f"  Started: {datetime.now().strftime('%H:%M:%S')}")
        print(f"{'='*60}")

        cmd = [sys.executable, "tools/auto_optimize_loop.py", "--data", data_path,
               "--search", args.search]
        if hours_per_combo is not None:
            cmd += ["--hours", str(hours_per_combo)]

        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[{i}/{total}] {label} finished in {elapsed/60:.1f}m  [{status}]")

        remaining = total - i
        if remaining > 0:
            if hours_per_combo is not None:
                eta = datetime.now() + timedelta(hours=remaining * hours_per_combo)
                print(f"  Remaining: {remaining} combos, ETA {eta.strftime('%H:%M:%S')}")
            else:
                print(f"  Remaining: {remaining} combos")

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


if __name__ == "__main__":
    main()
