from __future__ import annotations

from decimal import Decimal
from types import SimpleNamespace

from src.execution.maker_taker_shadow import advance_shadow, submit_shadow


def _f(ts, *, low="99.8", high="100.2", close="100", spread="0.10"):
    return SimpleNamespace(candle_ts=ts, low_15m=Decimal(low), high_15m=Decimal(high), close_15m=Decimal(close), current_price=Decimal(close), spread_pct=Decimal(spread), sell_impact_1k_pct=Decimal("0.02"), buy_impact_1k_pct=Decimal("0.02"))


def test_maker_shadow_requires_future_touch_and_tracks_exit_costs():
    state = {}
    submitted = submit_shadow(state, coin="ETH", side="long", feature=_f(1), size=Decimal("0.15"), stop_loss=Decimal("99"), take_profit=Decimal("101"), source_window_id="w1", strategy_id="research_v78_regime_router")
    assert submitted["event"] == "maker_pending"
    assert submitted["limit_price"] == "99.9500"
    assert advance_shadow(state, {"ETH": _f(1)}) == []
    events = advance_shadow(state, {"ETH": _f(2, low="99.90")})
    assert events[0]["event"] == "maker_fill"
    assert events[0]["entry_order_type"] == "limit_Alo"
    events = advance_shadow(state, {"ETH": _f(3, high="101.2", close="101")})
    assert events[0]["event"] == "maker_exit"
    assert events[0]["exit_order_type"] == "market_taker"
    assert Decimal(events[0]["maker_entry_fee_usd"]) > 0
    assert Decimal(events[0]["net_pnl_usd"]) < Decimal(events[0]["gross_pnl_usd"])
    assert state["pending"] == {}
    assert state["open"] == {}


def test_maker_shadow_cancels_after_two_unfilled_future_bars():
    state = {}
    submit_shadow(state, coin="BTC", side="long", feature=_f(10), size=Decimal("0.1"), stop_loss=Decimal("98"), take_profit=Decimal("102"), source_window_id="w", strategy_id="s", max_wait_bars=2)
    assert advance_shadow(state, {"BTC": _f(11, low="100.01")}) == []
    events = advance_shadow(state, {"BTC": _f(12, low="100.01")})
    assert events[0]["event"] == "maker_cancel"
    assert events[0]["reason"] == "not_filled_before_expiry"
