"""evaluate_buy — 3개 매수 조건 경계."""
from conditions import evaluate_buy

BUY_PARAMS = {"rsi_oversold": 30, "breakout_vol_mult": 1.5, "pullback_pct": 0.02}


def _ctx(**over):
    base = dict(
        ticker="005930", name="삼성전자", price=100.0, day_open=99.0,
        today_volume=1000.0, closes=[], highs=[], lows=[], volumes=[],
        avg_price=None, qty=None, holding_high=None, climax_vol_mult=3.0,
    )
    base.update(over)
    return base


def _conditions(firing):
    return {f["condition"] for f in firing}


def test_ma20_pullback_fires():
    # 정배열(ma20>ma50>ma200), 최근 저가가 ma20 근처, price가 ma20 위로 반등
    closes = [90.0] * 200 + [100.0] * 20   # ma20=100, ma50/ma200 낮음 → 정배열
    lows = [90.0] * 217 + [100.5, 100.4, 100.3]  # 최근 3봉 저가 ~ma20*(1.02)=102 이하
    ctx = _ctx(price=101.0, closes=closes, highs=closes, lows=lows,
               volumes=[1.0] * len(closes))
    assert "buy_ma20_pullback" in _conditions(evaluate_buy(ctx, BUY_PARAMS))


def test_ma20_pullback_skips_when_not_aligned():
    closes = [100.0] * 200 + [90.0] * 20   # 역배열
    ctx = _ctx(price=91.0, closes=closes, highs=closes, lows=closes,
               volumes=[1.0] * len(closes))
    assert "buy_ma20_pullback" not in _conditions(evaluate_buy(ctx, BUY_PARAMS))


def test_breakout_fires():
    closes = [50.0] * 25
    highs = [60.0] * 25           # 직전 20봉 최고 60
    vols = [100.0] * 25           # avg20=100
    ctx = _ctx(price=61.0, today_volume=200.0, closes=closes, highs=highs,
               lows=closes, volumes=vols)   # 61>60, 200>1.5*100
    assert "buy_breakout" in _conditions(evaluate_buy(ctx, BUY_PARAMS))


def test_breakout_skips_on_low_volume():
    highs = [60.0] * 25
    ctx = _ctx(price=61.0, today_volume=120.0, closes=[50.0] * 25, highs=highs,
               lows=[50.0] * 25, volumes=[100.0] * 25)  # 120 < 1.5*100=150
    assert "buy_breakout" not in _conditions(evaluate_buy(ctx, BUY_PARAMS))


def test_rsi_bounce_fires():
    # 14봉 급락으로 RSI<30 찍고 5봉 반등하여 30 위로 복귀
    closes = [100.0]
    for _ in range(14):
        closes.append(closes[-1] * 0.97)   # 하락 → RSI 저하
    for _ in range(5):
        closes.append(closes[-1] * 1.05)   # 반등 → RSI 30 위로
    ctx = _ctx(price=closes[-1], closes=closes, highs=closes, lows=closes,
               volumes=[1.0] * len(closes))
    assert "buy_rsi_bounce" in _conditions(evaluate_buy(ctx, BUY_PARAMS))


def test_empty_series_no_fire():
    assert evaluate_buy(_ctx(), BUY_PARAMS) == []
