#!/usr/bin/env python3
"""Optimize SimpleEMA v4 (regime dual entry + partial TP)."""

from __future__ import annotations

import argparse
import json
import random
import sys
from dataclasses import asdict
from datetime import datetime
from pathlib import Path

import MetaTrader5 as mt5
import pandas as pd

ROOT = Path(__file__).resolve().parents[3]
LAB = Path(__file__).resolve().parent
sys.path.insert(0, str(ROOT / "backtesting" / "MT5"))
sys.path.insert(0, str(LAB))

from cluster_audit.backtest_core import CostModel, load_bars, resolve_symbol  # noqa: E402
from run_backtest import pip_size  # noqa: E402
from strategy_v4 import V4Params, load_v4_cache, market_from_cache, sample_v4, simulate_v4, write_v4_set  # noqa: E402


def main() -> None:
    ap = argparse.ArgumentParser()
    ap.add_argument("--trials", type=int, default=3000)
    ap.add_argument("--min-trades", type=int, default=400)
    ap.add_argument("--max-trades", type=int, default=2500)
    ap.add_argument("--seed", type=int, default=42)
    args = ap.parse_args()
    out = LAB
    rng = random.Random(args.seed)

    if not mt5.initialize():
        raise SystemExit("MT5 init failed")
    try:
        sym = resolve_symbol("EURUSD")
        df = load_bars(sym, mt5.TIMEFRAME_M15, datetime(2020, 1, 1), datetime(2026, 1, 1))
        costs = CostModel.for_symbol(sym)
        pip = pip_size(sym)
        point = float(mt5.symbol_info(sym).point)
        print(f"v4 optimize {sym} M15 trials={args.trials} trades={args.min_trades}-{args.max_trades}")
        cache = load_v4_cache(df)

        best_profit = None
        best_balanced = None
        target = None

        for n in range(1, args.trials + 1):
            p = sample_v4(rng)
            md = market_from_cache(cache, p)
            r = simulate_v4(md, sym, p, costs, pip, point)

            if args.min_trades <= r.total_trades <= args.max_trades and r.net_profit > 0 and r.profit_factor >= 1.05:
                if target is None or r.net_profit > target[0].net_profit:
                    target = (r, p)
                    print(f"  HIT {n}: net=${r.net_profit:,.0f} t={r.total_trades} PF={r.profit_factor:.2f}")

            if r.net_profit > 0:
                if best_balanced is None or r.total_trades > best_balanced[0].total_trades or (
                    r.total_trades == best_balanced[0].total_trades and r.net_profit > best_balanced[0].net_profit
                ):
                    best_balanced = (r, p)

            if best_profit is None or r.net_profit > best_profit[0].net_profit:
                best_profit = (r, p)

            if n % 500 == 0:
                b = best_balanced or best_profit
                print(f"  ... {n}/{args.trials} best_bal t={b[0].total_trades} net=${b[0].net_profit:,.0f} hit={'yes' if target else 'no'}")

        final_r, final_p = target or best_balanced or best_profit
        assert final_r and final_p

        write_v4_set(final_p, out / "SimpleEMA_optimized.set")
        payload = {
            "version": 4,
            "target_met": target is not None,
            "params": asdict(final_p),
            "metrics": {k: v for k, v in asdict(final_r).items() if k != "trades"},
        }
        (out / "best_params.json").write_text(json.dumps(payload, indent=2), encoding="utf-8")

        (out / "best_run").mkdir(exist_ok=True)
        rows = [
            {
                "side": t["side"],
                "open_time": df.index[t["open_i"]],
                "close_time": df.index[t["close_i"]],
                "profit": t["profit"],
                "exit_reason": t["exit_reason"],
            }
            for t in final_r.trades
        ]
        pd.DataFrame(rows).to_csv(out / "best_run" / "trades.csv", index=False)

        print(
            f"\n{'TARGET' if target else 'BEST'}: net=${final_r.net_profit:,.2f} "
            f"trades={final_r.total_trades} PF={final_r.profit_factor:.2f} WR={final_r.win_rate:.1f}% DD={final_r.max_drawdown_pct:.1f}%"
        )
    finally:
        mt5.shutdown()


if __name__ == "__main__":
    main()
