#!/usr/bin/env python3
"""실매 ↔ 백테 포트폴리오·유니버스 슬롯 정합 검증."""
from __future__ import annotations

import os
import sys

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from datetime import datetime as dt
from typing import Dict, List

from kis_trader.utils.live_portfolio_common import (
    filter_candidates_by_history_universe,
    live_portfolio_budget_full,
    live_universe_slot_align_enabled,
    portfolio_strategy_key,
    resolve_live_buy_qty,
    resolve_live_total_budget_krw,
    slot_key_from_dt,
)


class _FakeDB:
    def __init__(self, rows: List[Dict]):
        self._rows = rows

    def get_universe_at(self, *, strategy_id: str, at_time: str) -> List[Dict]:
        eligible = [r for r in self._rows if r["event_time"] <= at_time]
        if not eligible:
            return []
        et = max(r["event_time"] for r in eligible)
        return [
            {"code": r["code"], "name": r["name"]}
            for r in eligible if r["event_time"] == et
        ]


def _ok(msg: str) -> None:
    print(f"  OK  {msg}")


def _fail(msg: str) -> None:
    print(f"  FAIL {msg}")
    raise SystemExit(1)


def main() -> None:
    print("=== live_portfolio_common 단위 ===")
    when = dt(2026, 7, 2, 9, 31, 25)
    sk = slot_key_from_dt(when, 1)
    if sk != "202607020931":
        _fail(f"slot_key {sk}")
    _ok(f"slot_key={sk}")

    if portfolio_strategy_key("SHORT") != "TAIL":
        _fail("SHORT→TAIL mapping")
    _ok("SHORT→TAIL")

    tb = resolve_live_total_budget_krw("BREAKOUT", max_stocks=20, slot_money=300_000)
    if tb <= 0:
        _fail(f"total_budget={tb}")
    _ok(f"BREAKOUT total_budget={tb:,.0f}")

    holdings = {"005930": {"buy_price": 70000, "qty": 5}}
    full = live_portfolio_budget_full(holdings, "BREAKOUT", 300_000, 20)
    _ok(f"budget_full={full}")

    qty, invest, rej = resolve_live_buy_qty(
        70000, {}, "BREAKOUT", 300_000, max_stocks=20, invest_cap=300_000,
    )
    if qty < 1 or rej:
        _fail(f"buy_qty qty={qty} rej={rej}")
    _ok(f"buy_qty qty={qty} invest={invest:,.0f}")

    db = _FakeDB([
        {"event_time": "2026-07-02 09:30:00", "code": "005930", "name": "삼성"},
        {"event_time": "2026-07-02 09:30:00", "code": "000660", "name": "SK"},
        {"event_time": "2026-07-02 09:31:10", "code": "005930", "name": "삼성"},
    ])
    cands = [
        {"code": "005930", "name": "삼성"},
        {"code": "035720", "name": "카카오"},
    ]
    out, dropped = filter_candidates_by_history_universe(
        cands, db, "BREAKOUT", when=when,
    )
    if len(out) != 1 or out[0]["code"] != "005930" or dropped != 1:
        _fail(f"universe filter out={out} dropped={dropped}")
    _ok("universe history ∩ live candidates")

    print("=== 전략 import ===")
    from kis_trader.strategies import (  # noqa: WPS433
        BreakoutStrategy,
        DbBandStrategy,
        MomentumStrategy,
        RangeBreakStrategy,
        ScalpingStrategy,
        TailCatchStrategy,
    )
    for cls in (
        BreakoutStrategy, ScalpingStrategy, MomentumStrategy,
        RangeBreakStrategy, TailCatchStrategy, DbBandStrategy,
    ):
        _ok(cls.__name__)

    print("=== 슬롯 정합 플래그 ===")
    for sid in ("BREAKOUT", "SCALP", "MOMENTUM", "RANGE_BREAK", "SHORT", "UPDOW", "DBBAND"):
        en = live_universe_slot_align_enabled(sid)
        print(f"  {sid}: universe_slot={en}")

    print("\n✅ verify_live_portfolio_align 전부 통과")


if __name__ == "__main__":
    try:
        main()
    except SystemExit:
        sys.exit(1)
