"""evaluate_sell — 5개 매도 조건 경계."""
from conditions import evaluate_sell

EXIT = {"stop_pct": 0.08, "take_pct": 0.25, "trailing_pct": 0.10,
        "climax_vol_x": 3.0, "climax_close_pct": 0.97}


def _ctx(**over):
    base = dict(
        ticker="000660", name="SK하이닉스", price=100.0, day_open=100.0,
        day_high=100.0, today_volume=100.0, closes=[100.0] * 60,
        highs=[100.0] * 60, lows=[100.0] * 60, volumes=[100.0] * 60,
        avg_price=100.0, qty=10, holding_high=100.0, climax_vol_mult=3.0,
    )
    base.update(over)
    return base


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


def test_stop_loss_fires():
    ctx = _ctx(price=90.0, avg_price=100.0)   # -10% <= -8%
    assert "sell_stop_loss" in _c(evaluate_sell(ctx, EXIT))


def test_stop_loss_skips_above_threshold():
    ctx = _ctx(price=95.0, avg_price=100.0)   # -5% > -8%
    assert "sell_stop_loss" not in _c(evaluate_sell(ctx, EXIT))


def test_take_profit_fires():
    ctx = _ctx(price=130.0, avg_price=100.0)  # +30% >= 25%
    assert "sell_take_profit" in _c(evaluate_sell(ctx, EXIT))


def test_trailing_stop_fires():
    ctx = _ctx(price=89.0, holding_high=100.0)  # 89 <= 100*0.9=90
    assert "sell_trailing_stop" in _c(evaluate_sell(ctx, EXIT))


def test_ma_break_severity_high():
    # price가 ma50/ma200 아래 → severity high (ma200 계산 위해 200봉 필요)
    closes = [200.0] * 200
    ctx = _ctx(price=100.0, closes=closes, avg_price=100.0, holding_high=100.0)
    firing = evaluate_sell(ctx, EXIT)
    mb = [f for f in firing if f["condition"] == "sell_ma_break"]
    assert mb and mb[0]["detail"]["severity"] == "high"


def test_climax_fires():
    # holdings_intel 정합: 거래량 3배 이상 + 종가 < 당일고가×0.97 (윗꼬리)
    ctx = _ctx(price=96.0, day_high=100.0, today_volume=400.0,
               volumes=[100.0] * 60)   # 400>=3*100, 96 < 100*0.97=97
    assert "sell_climax" in _c(evaluate_sell(ctx, EXIT))


def test_climax_skips_when_not_reversal():
    # 종가가 당일고가의 97% 이상 → 윗꼬리 아님
    ctx = _ctx(price=99.0, day_high=100.0, today_volume=400.0,
               volumes=[100.0] * 60)   # 99 >= 100*0.97=97 → 반전 아님
    assert "sell_climax" not in _c(evaluate_sell(ctx, EXIT))


def test_climax_uses_exit_params_vol_x():
    # exit_params.climax_vol_x=5.0 → 400 < 5*100=500 → 미발화
    exit5 = {**EXIT, "climax_vol_x": 5.0}
    ctx = _ctx(price=96.0, day_high=100.0, today_volume=400.0,
               volumes=[100.0] * 60)
    assert "sell_climax" not in _c(evaluate_sell(ctx, exit5))


def test_climax_uses_exit_params_close_pct():
    # climax_close_pct=0.90 → 임계 90, price=95 → 95<90? No → 미발화
    exit90 = {**EXIT, "climax_close_pct": 0.90}
    ctx = _ctx(price=95.0, day_high=100.0, today_volume=400.0,
               volumes=[100.0] * 60)
    assert "sell_climax" not in _c(evaluate_sell(ctx, exit90))
    # 기본 0.97이면 95 < 97 → 발화
    assert "sell_climax" in _c(evaluate_sell(ctx, EXIT))


def test_no_avg_no_pnl_conditions():
    # avg_price None(보유정보 없음) → stop/take 미발화
    ctx = _ctx(price=50.0, avg_price=None, holding_high=None,
               closes=[100.0] * 60)
    conds = _c(evaluate_sell(ctx, EXIT))
    assert "sell_stop_loss" not in conds and "sell_take_profit" not in conds
