"""预估盈亏比(前端 manual_order_rr_preview.js)公式与后端 calc_rr_ratio 口径一致."""


def _calc_rr(direction: str, entry: float, sl: float, tp: float):
    if entry <= 0 or sl <= 0 or tp <= 0:
        return None
    if direction == "short":
        risk = sl - entry
        reward = entry - tp
    else:
        risk = entry - sl
        reward = tp - entry
    if risk <= 0 or reward <= 0:
        return None
    return round(reward / risk, 4)


def _calc_rr_from_pct(sl_pct: float, tp_pct: float):
    if sl_pct <= 0 or tp_pct <= 0:
        return None
    return tp_pct / sl_pct


def test_long_price_mode_rr():
    assert _calc_rr("long", 100.0, 95.0, 110.0) == 2.0


def test_short_price_mode_rr():
    assert _calc_rr("short", 100.0, 105.0, 90.0) == 2.0


def test_invalid_geometry_returns_none():
    assert _calc_rr("long", 100.0, 105.0, 110.0) is None
    assert _calc_rr("short", 100.0, 95.0, 98.0) is None


def test_pct_mode_rr():
    assert _calc_rr_from_pct(2.0, 4.0) == 2.0
    assert _calc_rr_from_pct(1.5, 3.0) == 2.0


def _calc_risk_fraction(direction: str, entry: float, sl: float):
    if entry <= 0 or sl <= 0:
        return None
    if direction == "short":
        risk = sl - entry
    else:
        risk = entry - sl
    if risk <= 0:
        return None
    return risk / entry


def _full_margin_risk_u(available: float, buffer: float, leverage: int, direction: str, entry: float, sl: float):
    rf = _calc_risk_fraction(direction, entry, sl)
    if rf is None:
        return None
    margin = round(available * buffer, 2)
    return round(margin * leverage * rf, 2)


def test_full_margin_risk_short_hype():
    # 可用约 23.06U × 0.9 缓冲 × 5x,入场 62.5,止损 63.6
    risk = _full_margin_risk_u(23.06, 0.9, 5, "short", 62.5, 63.6)
    assert risk is not None
    assert 1.5 <= risk <= 2.5
