#!/usr/bin/env python3
"""optimize.py — optimizes strategy parameters via grid-search + walk-forward (IS/OOS).

Parameters are scanned on the first 70% of the data (in-sample); the best combination is
validated on the unseen final 30% (out-of-sample). DOES NOT SEND ORDERS; only runs backtests.

Example:
  python scripts/optimize.py                          # first 8 symbols from the screener
  python scripts/optimize.py --symbols BTCUSDT,ETHUSDT,SOLUSDT --limit 1500
  python scripts/optimize.py --is-frac 0.6 --top 15
"""
from __future__ import annotations

import argparse
import pathlib
import sys

sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent.parent))

from rich.console import Console

from coinbot.config import load_settings
from coinbot.exchange import Exchange
from coinbot.optimize import print_optimization, run_optimization
from coinbot.screener import screen_universe

console = Console()


def _parse_args(argv: list[str] | None = None) -> argparse.Namespace:
    p = argparse.ArgumentParser(
        prog="optimize.py",
        description="Strateji parametre optimizasyonu (grid-search + IS/OOS doğrulama).",
    )
    p.add_argument("--mode", default=None, choices=["dry_run", "testnet", "live"],
                   help="Çalışma modunu config/env üzerine yaz (opsiyonel).")
    p.add_argument("--symbols", default=None,
                   help="Virgülle ayrılmış semboller (verilmezse screener ilk N).")
    p.add_argument("--limit", type=int, default=1000,
                   help="Sembol başına çekilecek toplam bar (varsayılan 1000).")
    p.add_argument("--is-frac", type=float, default=0.7,
                   help="In-sample oranı 0..1 (varsayılan 0.7).")
    p.add_argument("--max-symbols", type=int, default=8,
                   help="screener'dan alınacak sembol sayısı (varsayılan 8).")
    p.add_argument("--top", type=int, default=10,
                   help="Liderlik tablosunda gösterilecek combo sayısı.")
    p.add_argument("--timeframe", default=None,
                   help="Zaman dilimini config üzerine yaz (ör. 1h, 4h).")
    p.add_argument("--regime", action="store_true",
                   help="Rejim filtresini AÇ (yalnızca regime_symbol boğasalken AL).")
    p.add_argument("--json", action="store_true",
                   help="Sonucu makine-okur JSON olarak bas (rich tablo yerine).")
    return p.parse_args(argv)


def main(argv: list[str] | None = None) -> int:
    args = _parse_args(argv)
    try:
        settings = load_settings(mode_override=args.mode)
    except (RuntimeError, ValueError) as exc:
        console.print(f"[bold red]Ayar/guvenlik hatasi:[/] {exc}")
        return 2

    # CLI overrides (for workflow cells): timeframe + regime filter.
    if args.timeframe:
        settings.timeframe = args.timeframe
    if args.regime:
        settings.strategy.use_regime_filter = True

    try:
        ex = Exchange(settings)
        if args.symbols:
            symbols = [s.strip().upper() for s in args.symbols.split(",") if s.strip()]
        else:
            symbols = screen_universe(ex, settings)[: args.max_symbols]
    except Exception as exc:  # noqa: BLE001 - user-friendly error
        console.print(f"[bold red]Sembol secimi/tarama hatasi:[/] {exc}")
        return 1

    if not symbols:
        console.print("[red]Optimizasyon için sembol bulunamadi.[/]")
        return 1

    console.print(
        f"Optimizasyon basliyor — {len(symbols)} sembol, {args.limit} bar, "
        f"IS={args.is_frac:.0%} / OOS={1 - args.is_frac:.0%}: {', '.join(symbols)}"
    )

    try:
        result = run_optimization(
            ex, symbols, settings, total_limit=args.limit, is_frac=args.is_frac
        )
    except (RuntimeError, ValueError) as exc:
        console.print(f"[bold red]Optimizasyon hatasi:[/] {exc}")
        return 1

    if args.json:
        import json
        out = {
            "timeframe": settings.timeframe,
            "regime": settings.strategy.use_regime_filter,
            "n_symbols": result.n_symbols,
            "n_combos": result.n_combos,
            "best_params": result.best_params,
            "in_sample": result.in_sample,
            "out_sample": result.out_sample,
        }
        # Single line, prefixed with "OPTJSON:" -> can be parsed out of log noise.
        print("OPTJSON:" + json.dumps(out, default=str))
    else:
        print_optimization(result, settings, console=console, top_n=args.top)
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
