#!/usr/bin/env python3
"""
kis_trader/backtest/dart_backtest_common.py — DART 웹백테 정렬
"""
from __future__ import annotations

from typing import Any, Dict, List, Optional

from database import TradeDB
from kis_trader.backtest import scalping_backtest_common as sbc
from kis_trader.engine import dart_engine as de


def load_dart_events(db: TradeDB, start: str, end: str) -> List[Dict[str, Any]]:
    try:
        from kis_trader.scan.dart_order_tracker import ensure_dart_disclosure_columns
        ensure_dart_disclosure_columns(db)
    except Exception:
        pass
    rows = db.conn.execute(
        """
        SELECT rcept_no, stock_code, corp_name, report_nm, rcept_dt, first_seen_at
        FROM dart_disclosures
        WHERE stock_code <> ''
          AND (filter_ok IS NULL OR filter_ok = 1)
          AND (
            (first_seen_at >= %s AND first_seen_at <= %s)
            OR (rcept_dt >= %s AND rcept_dt <= %s)
          )
        ORDER BY first_seen_at ASC
        """,
        (
            start + " 00:00:00",
            end + " 23:59:59",
            start.replace("-", ""),
            end.replace("-", ""),
        ),
    ).fetchall()
    return [dict(r) for r in rows]


def event_to_candle_time(ev: Dict[str, Any]) -> str:
    fs = str(ev.get("first_seen_at") or "")
    if fs:
        s = fs.replace("-", "").replace(":", "").replace(" ", "")
        if len(s) >= 12:
            return s[:12]
    rd = str(ev.get("rcept_dt") or "")
    if len(rd) == 8:
        return rd + "0900"
    return ""


def _load_code_candles(db: TradeDB, code: str, start: str, end: str) -> List[Dict]:
    sk = start.replace("-", "") + "0900"
    ek = end.replace("-", "") + "1530"
    rows = db.conn.execute(
        """
        SELECT candle_time, open, high, low, close, volume
        FROM ws_candles
        WHERE timeframe=1 AND code=%s
          AND candle_time >= %s AND candle_time <= %s
        ORDER BY candle_time ASC
        """,
        (code, sk, ek),
    ).fetchall()
    out = []
    for r in rows:
        out.append({
            "candle_time": str(r["candle_time"]),
            "open": float(r["open"] or 0),
            "high": float(r["high"] or 0),
            "low": float(r["low"] or 0),
            "close": float(r["close"] or 0),
            "volume": float(r["volume"] or 0),
            "is_confirmed": 1,
        })
    return out


def run_dart_backtest_web_aligned(
    *,
    start: str,
    end: str,
    params: Optional[Dict[str, Any]] = None,
    env_row: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
    p = dict(params or de.get_dart_defaults_from_db(env_row=env_row))
    db = TradeDB()
    events: List[Dict[str, Any]] = []
    all_trades: List[Dict[str, Any]] = []
    try:
        fee_rate, sell_tax, slot = sbc.fee_and_slot_from_env(env_row, strategy="DART")
        if params and params.get("slot_money"):
            slot = float(params["slot_money"])
        events = load_dart_events(db, start, end)
        codes_done = set()
        for ev in events:
            code = str(ev.get("stock_code") or "").strip()
            if not code:
                continue
            ect = event_to_candle_time(ev)
            if not ect:
                continue
            key = (code, ect[:8])
            if key in codes_done:
                continue
            codes_done.add(key)
            candles = _load_code_candles(db, code, start, end)
            if not candles:
                continue
            trades = de.run_dart_backtest_code(
                candles,
                p,
                event_candle_time=ect,
                slot_money=slot,
                fee_rate=fee_rate,
                sell_tax=sell_tax,
            )
            for t in trades:
                t["code"] = code
                t["name"] = ev.get("corp_name") or code
                t["rcept_no"] = ev.get("rcept_no")
                all_trades.append(t)
    finally:
        db.close()

    wins = sum(1 for t in all_trades if float(t.get("pnl") or 0) > 0)
    n = len(all_trades)
    pnl = sum(float(t.get("pnl") or 0) for t in all_trades)
    return {
        "ok": True,
        "strategy": "DART",
        "start": start,
        "end": end,
        "trades": all_trades,
        "trade_count": n,
        "win_rate": (wins / n * 100.0) if n else 0.0,
        "total_pnl": pnl,
        "events": len(events),
        "params": p,
    }
