from decimal import Decimal

from src.execution.order_intent import OrderIntent
from src.risk.pretrade_risk_gate import PretradeRiskGate, RiskContext


def _intent(**overrides):
    base = dict(
        strategy_id="candidate_v76_hl_confirmed_squeeze_hybrid",
        symbol="BTC/USDC:USDC",
        coin="BTC",
        side="buy",
        reduce_only=False,
        order_type="market",
        tif="Ioc",
        size=Decimal("0.01"),
        price=None,
        trigger_price=None,
        stop_loss=Decimal("99000"),
        take_profit=None,
        client_order_id="v76-BTC-1",
        reason="confirmed_squeeze_breakout",
        risk_usd=Decimal("1.25"),
        estimated_notional_usd=Decimal("100"),
    )
    base.update(overrides)
    return OrderIntent(**base)


def test_pretrade_gate_allows_safe_entry_intent():
    gate = PretradeRiskGate(min_order_notional_usd=Decimal("10"), max_parallel_positions=1)

    decision = gate.evaluate(_intent(), RiskContext(open_positions=0, kill_switch_active=False, daily_loss_exceeded=False))

    assert decision.allowed is True
    assert decision.reasons == ()


def test_pretrade_gate_blocks_min_notional_and_parallel_positions():
    gate = PretradeRiskGate(min_order_notional_usd=Decimal("10"), max_parallel_positions=1)

    decision = gate.evaluate(_intent(estimated_notional_usd=Decimal("9.99")), RiskContext(open_positions=1, kill_switch_active=False, daily_loss_exceeded=False))

    assert decision.allowed is False
    assert set(decision.reasons) == {"min_notional", "max_parallel_positions"}


def test_pretrade_gate_blocks_kill_switch_and_daily_loss():
    gate = PretradeRiskGate(min_order_notional_usd=Decimal("10"), max_parallel_positions=1)

    decision = gate.evaluate(_intent(), RiskContext(open_positions=0, kill_switch_active=True, daily_loss_exceeded=True))

    assert decision.allowed is False
    assert set(decision.reasons) == {"kill_switch", "daily_loss_exceeded"}


def test_pretrade_gate_blocks_max_notional_and_max_risk():
    gate = PretradeRiskGate(min_order_notional_usd=Decimal("10"), max_parallel_positions=1, max_order_notional_usd=Decimal("15"), max_risk_usd=Decimal("0.50"))

    decision = gate.evaluate(_intent(estimated_notional_usd=Decimal("15.01"), risk_usd=Decimal("0.51")), RiskContext(open_positions=0, kill_switch_active=False, daily_loss_exceeded=False))

    assert decision.allowed is False
    assert set(decision.reasons) == {"max_notional", "max_risk"}
