#!/usr/bin/env python3
"""Optuna 결과 JSON vs 현재 DB — 백테 비교표를 로그 파일 끝에 append (DB 미저장)."""
from __future__ import annotations

import argparse
import json
import sys
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
if str(ROOT) not in sys.path:
    sys.path.insert(0, str(ROOT))

from database import TradeDB
from kis_trader.backtest import tail_backtest_common as tbc
from kis_trader.engine import tail_engine as te


COMPARE_KEYS = [
    "entry_mode",
    "min_drop_rate",
    "min_recovery_ratio",
    "tail_ratio_min",
    "tail_pct_min",
    "max_rec_3m",
    "shoulder_min_high",
    "shoulder_cut_pct",
    "stop_atr_mult",
    "target_atr_mult",
    "atr_sl_min_pct",
    "atr_sl_max_pct",
    "atr_tp_min_pct",
    "atr_tp_max_pct",
    "max_daily_change",
    "max_loss_krw",
    "limit_atr_mult",
    "tail_vol_mult",
    "tail_vol_win",
    "ratchet_tiers",
    "rsi_threshold",
    "cooldown_min",
    "bar_chg_min_pct",
    "bar_chg_max_pct",
    "symbol_daily_loss_limit_krw",
    "symbol_daily_loss_limit_pct",
    "reentry_min_edge_krw",
    "reentry_require_nonneg",
    "trail_tiers",
    "trail_drop_pct",
    "trail_arm_krw",
    "pattern_pin",
    "pattern_engulfing",
    "pattern_piercing",
    "max_daily",
    "max_spread_pct",
    "min_bid_ask_ratio",
]


def _same(a, b) -> bool:
    if a == b:
        return True
    try:
        return abs(float(a) - float(b)) < 1e-9
    except Exception:
        return str(a) == str(b)


def _run(candles_by_code, universe, base, port, fee, tax, slot, budget, meta, overrides):
    params = dict(base)
    tbc.merge_tail_portfolio_into_params(params, port)
    params.update(overrides or {})
    trades = tbc.run_tail_backtest_web_aligned(
        candles_by_code,
        params,
        universe,
        slot_money=slot,
        fee_rate=fee,
        sell_tax=tax,
        total_budget_krw=budget,
        meta_out=dict(meta),
    )
    wins = [t for t in trades if float(t.get("pnl") or 0) > 0]
    pnl = sum(float(t.get("pnl") or 0) for t in trades)
    wr = (len(wins) / len(trades) * 100.0) if trades else 0.0
    return {
        "trades": len(trades),
        "wins": len(wins),
        "wr": wr,
        "pnl": pnl,
        "params": {k: params.get(k) for k in COMPARE_KEYS},
    }


def main() -> int:
    ap = argparse.ArgumentParser()
    ap.add_argument("--json", required=True, help="optuna_tail_*.json 경로")
    ap.add_argument("--log", required=True, help="append 대상 로그 경로")
    ap.add_argument("--date", default="2026-07-10", help="백테 일자 YYYY-MM-DD")
    args = ap.parse_args()

    json_path = Path(args.json)
    log_path = Path(args.log)
    data = json.loads(json_path.read_text(encoding="utf-8"))
    best = (data.get("results") or [None])[0]
    if not best:
        msg = "❌ Optuna results 비어 있음 — 비교 스킵\n"
        with log_path.open("a", encoding="utf-8") as f:
            f.write(msg)
        print(msg, end="")
        return 1

    best_params = best.get("params") or {}
    day = args.date
    start_key = day.replace("-", "") + "0000"
    end_key = day.replace("-", "") + "2359"
    start_ymd, end_ymd = start_key[:8], end_key[:8]

    db = TradeDB()
    base = te.get_tail_defaults_from_db(db)
    universe, src, n_slots, _ = tbc.resolve_tail_universe(
        start_ymd, end_ymd, use_saved_history=True, strategy_id="SHORT",
    )
    tf = int(base.get("timeframe") or 3)
    rsi = int(base.get("rsi_period") or 14)
    candles_by_code, _, _ = tbc.load_tail_candles_by_code(
        db, start_key, end_key, tf, rsi_period=rsi,
    )
    row = db.conn.execute("SELECT * FROM env_config ORDER BY id DESC LIMIT 1").fetchone()
    r = dict(row) if row else {}
    fee, tax, _ = tbc.fee_and_slot_from_env_row(r)
    port = tbc.resolve_tail_portfolio_params(r, base)
    slot = float(port["slot_money"])
    budget = float(port["total_budget_krw"])
    meta = {"db": db, "start_key": start_key, "end_key": end_key}

    cur = _run(candles_by_code, universe, base, port, fee, tax, slot, budget, meta, {})
    bst = _run(
        candles_by_code, universe, base, port, fee, tax, slot, budget, meta, best_params,
    )
    delta = bst["pnl"] - cur["pnl"]
    trial_no = best.get("optuna_trial_number") or data.get("optuna_best_trial_number")
    mode = data.get("mode") or "?"
    elapsed = data.get("elapsed_sec")

    lines = []
    lines.append("")
    lines.append("=" * 72)
    lines.append(f"[COMPARE] CURRENT_DB vs OPTUNA_{mode.upper()}_BEST | {day} | DB미저장")
    lines.append("=" * 72)
    lines.append(f"json={json_path}")
    lines.append(f"universe={src} slots={n_slots} | trial=#{trial_no} elapsed={elapsed}s")
    lines.append("")
    lines.append("| 구분 | 거래 | 승 | 승률 | 손익 |")
    lines.append("|------|------|----|------|------|")
    lines.append(
        f"| CURRENT_DB | {cur['trades']} | {cur['wins']} | {cur['wr']:.1f}% | {cur['pnl']:+,.0f} |"
    )
    lines.append(
        f"| OPTUNA_BEST | {bst['trades']} | {bst['wins']} | {bst['wr']:.1f}% | {bst['pnl']:+,.0f} |"
    )
    lines.append(f"| Δ(best-current) |  |  |  | {delta:+,.0f} |")
    lines.append("")
    lines.append("| 파라미터 | CURRENT_DB | OPTUNA_BEST | diff |")
    lines.append("|----------|------------|--------------|------|")
    for k in COMPARE_KEYS:
        a = cur["params"].get(k)
        b = bst["params"].get(k)
        mark = "" if _same(a, b) else "<<"
        lines.append(f"| {k} | {a} | {b} | {mark} |")
    lines.append("")
    lines.append("DB 저장 없음 (--apply-best 미사용)")
    lines.append("=" * 72)
    lines.append("")
    text = "\n".join(lines)
    with log_path.open("a", encoding="utf-8") as f:
        f.write(text)
    print(text, end="")
    return 0


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