from lib.strategy.strategy_roll_lib import (
    preview_roll,
    roll_breakout_invalidate,
    roll_breakout_trigger_crossed,
    roll_fib_invalidate,
    roll_fib_trigger_crossed,
    solve_add_amount_for_total_risk,
    validate_roll_geometry,
)


def test_solve_add_amount_long_one_risk():
    q2, err = solve_add_amount_for_total_risk(
        "long", 1.0, 3000.0, 3100.0, 2950.0, 200.0, 1.0
    )
    assert err is None
    avg = (1 * 3000 + q2 * 3100) / (1 + q2)
    loss = (avg - 2950) * (1 + q2)
    assert abs(loss - 200.0) < 0.01


def test_preview_roll_market_short():
    preview, err = preview_roll(
        direction="short",
        symbol="HYPE/USDT",
        qty_existing=3.0,
        entry_existing=65.0,
        initial_take_profit=60.0,
        add_mode="market",
        new_stop_loss=66.5,
        risk_percent=2.0,
        capital_base_usdt=1000.0,
        add_price=64.0,
        legs_done=1,
    )
    assert err is None
    assert preview["add_mode_label"] == "市价加仓"
    sl = preview["new_stop_loss"]
    avg = preview["avg_entry_after"]
    qty = preview["qty_after"]
    loss = (sl - avg) * qty
    assert abs(loss - 20.0) < 0.01


def test_fib_cross_long_down():
    assert roll_fib_trigger_crossed("long", 101.0, 100.0, 100.5) is True
    assert roll_fib_trigger_crossed("long", 100.6, 100.6, 100.5) is False


def test_breakout_cross_long_up():
    assert roll_breakout_trigger_crossed("long", 99.0, 100.5, 100.0) is True
    assert roll_breakout_trigger_crossed("long", 99.0, 100.0, 100.0) is False
    assert roll_breakout_invalidate("long", 98.0, 99.0) is True
    assert roll_fib_invalidate("long", 110.0, 105.0, 95.0) is True


def test_breakout_short_below_breakthrough():
    assert roll_breakout_trigger_crossed("short", 81.0, 80.57, 80.65) is True
    assert roll_breakout_trigger_crossed("short", 80.64, 80.57, 80.65) is True
    assert roll_breakout_trigger_crossed("short", 80.57, 80.57, 80.65) is True
    assert roll_breakout_trigger_crossed("short", 81.0, 80.70, 80.65) is False


def test_preview_breakout_mode_label():
    preview, err = preview_roll(
        direction="long",
        symbol="ETH/USDT",
        qty_existing=1.0,
        entry_existing=3000.0,
        initial_take_profit=3500.0,
        add_mode="breakout",
        new_stop_loss=2980.0,
        breakthrough_price=3100.0,
        risk_percent=10.0,
        capital_base_usdt=1000.0,
        add_price=3050.0,
    )
    assert err is None
    assert preview["add_mode_label"] == "突破加仓"


def test_breakout_geometry_short_mark_above_breakout():
    err = validate_roll_geometry(
        "short",
        "breakout",
        new_stop_loss=568.0,
        breakthrough_price=551.0,
        entry_existing=560.0,
        initial_take_profit=540.0,
        mark_price=560.0,
    )
    assert err is None


def test_breakout_geometry_short_rejects_mark_at_or_below_breakout():
    err = validate_roll_geometry(
        "short",
        "breakout",
        new_stop_loss=568.0,
        breakthrough_price=551.0,
        entry_existing=560.0,
        initial_take_profit=540.0,
        mark_price=551.0,
    )
    assert err is not None
    assert "高于突破价" in err


def test_breakout_geometry_long_rejects_mark_at_or_above_breakout():
    err = validate_roll_geometry(
        "long",
        "breakout",
        new_stop_loss=2980.0,
        breakthrough_price=3100.0,
        entry_existing=3000.0,
        initial_take_profit=3500.0,
        mark_price=3100.0,
    )
    assert err is not None
    assert "低于突破价" in err
