#!/usr/bin/env python3
"""
스모크: 1M→N분 완전버킷 롤업 + confirm/merge volume upsert.

근본원인(2026-07-16 샘표): 불완전 롤업 삽입 + 동일 candle_time append 중복
→ RAM prior volume 왜곡 → 실매 vol 통과 / 백테 탈락.

실행:
  python3 -u scripts/smoke_candle_upsert_rollup.py
"""
from __future__ import annotations

import sys
from pathlib import Path

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

from kis_trader.engine.candle_rollup import floor_candle_time_to_tf, rollup_1m_bars_to_tf
from kis_trader.ws.kis_ws import CandleAggregator


def bar(ct, o, h, l, c, v, src="ws"):
    return {
        "candle_time": ct,
        "open": o,
        "high": h,
        "low": l,
        "close": c,
        "volume": v,
        "source": src,
    }


def main() -> None:
    assert floor_candle_time_to_tf("202607160912", 3) == "202607160912"
    assert floor_candle_time_to_tf("202607160913", 3) == "202607160912"
    assert floor_candle_time_to_tf("202607160914", 3) == "202607160912"

    partial = [
        bar("202607160912", 100, 101, 99, 100, 100),
        bar("202607160913", 100, 102, 99, 101, 200),
    ]
    assert rollup_1m_bars_to_tf(partial, 3) == []

    full = partial + [bar("202607160914", 101, 110, 100, 105, 4226)]
    rolled = rollup_1m_bars_to_tf(full, 3)
    assert len(rolled) == 1
    assert rolled[0]["candle_time"] == "202607160912"
    assert rolled[0]["volume"] == 100 + 200 + 4226

    more = full + [
        bar("202607160915", 105, 106, 104, 105, 50),
        bar("202607160916", 105, 107, 104, 106, 60),
    ]
    assert len(rollup_1m_bars_to_tf(more, 3)) == 1

    agg = CandleAggregator(db=None, timeframes=[1, 3])
    code = "007540"
    assert agg.merge_confirmed_bars(
        code, 3,
        [bar("202607160912", 43000, 44000, 42000, 43500, 515, "rollup_1m")],
        log_tag="smoke_partial",
    ) == 1
    assert agg.merge_confirmed_bars(
        code, 3,
        [bar("202607160912", 43000, 44500, 42000, 43800, 4526, "rest")],
        log_tag="smoke_full",
    ) == 1
    buf = agg._confirmed[(code, 3)]
    assert len(buf) == 1 and buf[0]["volume"] == 4526
    assert agg.merge_confirmed_bars(
        code, 3,
        [bar("202607160912", 43000, 44000, 42000, 43700, 100, "ws")],
        log_tag="smoke_small",
    ) == 0
    assert buf[0]["volume"] == 4526

    agg2 = CandleAggregator(db=None, timeframes=[3])
    key = (code, 3)
    agg2.merge_confirmed_bars(
        code, 3,
        [bar("202607160912", 43000, 44000, 42000, 43500, 515, "rollup_1m")],
    )
    with agg2._lock:
        confirmed = agg2._confirm_current_bucket(key, {
            "candle_time": "202607160912",
            "open": 43000,
            "high": 44200,
            "low": 42000,
            "close": 43600,
            "volume": 800,
            "source": "ws",
        })
    assert len(agg2._confirmed[key]) == 1
    assert confirmed["volume"] == 800
    with agg2._lock:
        agg2._confirm_current_bucket(key, {
            "candle_time": "202607160912",
            "open": 43000,
            "high": 44100,
            "low": 42000,
            "close": 43400,
            "volume": 100,
            "source": "ws",
        })
    assert agg2._confirmed[key][0]["volume"] == 800

    # 진행 중 분봉은 REST/merge confirmed 에 넣지 않음 (장초 직전봉% 왜곡 방지)
    import datetime as _dt
    agg3 = CandleAggregator(db=None, timeframes=[1])
    code2 = "333050"
    frozen = _dt.datetime(2026, 7, 16, 9, 0, 34)
    # 전일 + 미완성 당일 09:00 을 넣으려 할 때 → 09:00 만 skip
    n = agg3.merge_confirmed_bars(
        code2, 1,
        [
            bar("202607151530", 5280, 5280, 5280, 5280, 960, "rest"),
            bar("202607160900", 5220, 5250, 5200, 5220, 10, "rest"),  # 진행분
        ],
        log_tag="smoke_skip_open",
        skip_incomplete_bucket=True,
        now=frozen,
    )
    assert n == 1
    buf3 = agg3._confirmed[(code2, 1)]
    assert len(buf3) == 1 and buf3[0]["candle_time"] == "202607151530"
    # 이미 들어간 진행분 purge
    agg3._confirmed[(code2, 1)].append(
        bar("202607160900", 5220, 5250, 5200, 5220, 10, "rest")
    )
    agg3.merge_confirmed_bars(
        code2, 1, [], log_tag="smoke_purge", skip_incomplete_bucket=True, now=frozen,
    )
    assert all(
        str(c["candle_time"])[:12] < "202607160900"
        for c in agg3._confirmed[(code2, 1)]
    )

    print("SMOKE_OK candle_upsert_rollup")


if __name__ == "__main__":
    main()
