"""Minimal deterministic self-test for the entry execution engine.

Run:
  PYTHONPATH=API python -m app.v1.services.entry_engine_selftest

This is a tiny in-memory harness (no DB, no Zerodha) that validates:
- entry_zone derivation
- trigger activation rules for BUY/SELL
- RR computation is non-negative when structure exists
"""

from __future__ import annotations

from app.v1.services.entry_engine import build_execution_plan


def _base_md(*, ema9: float, ema21: float, vwap: float, close: float, piv_p: float = 100.0) -> dict:
    return {
        "candles": {
            "5minute": [
                {"o": close - 1.0, "h": close - 0.5, "l": close - 2.0, "c": close - 1.0},
                {"o": close, "h": close + 0.5, "l": close - 0.5, "c": close},
            ],
            "15minute": [
                {"o": close - 2.0, "h": close - 1.0, "l": close - 3.0, "c": close - 2.0},
                {"o": close - 1.0, "h": close + 1.0, "l": close - 2.0, "c": close},
            ],
            "day": [{"o": close - 10.0, "h": close + 10.0, "l": close - 10.0, "c": close - 2.0}],
        },
        "indicators": {
            "5minute": {
                "ema": {"9": ema9, "21": ema21},
                "vwap": vwap,
                "close": close,
            }
        },
        "pivots": {"day": {"P": piv_p, "R1": piv_p + 5.0, "R2": piv_p + 10.0, "S1": piv_p - 5.0, "S2": piv_p - 10.0}},
    }


def test_buy_waiting() -> None:
    # EMA pullback zone exists; last close below zone high => WAITING.
    md = _base_md(ema9=100.5, ema21=100.0, vwap=100.2, close=100.2)
    # ensure last 5m candle close is 100.2 (below zone_high 100.5)
    md["candles"]["5minute"][-1]["c"] = 100.2
    plan = build_execution_plan(decision="BUY", market_data=md)
    assert plan is not None
    assert plan.state == "WAITING_FOR_ENTRY"
    assert plan.entry_zone["low"] > 0 and plan.entry_zone["high"] > 0
    assert plan.entry_trigger_reason == []


def test_buy_activated_close_above_zone() -> None:
    md = _base_md(ema9=100.5, ema21=100.0, vwap=100.2, close=101.0)
    # last close above zone_high (100.5)
    md["candles"]["5minute"][-1]["c"] = 101.0
    plan = build_execution_plan(decision="BUY", market_data=md)
    assert plan is not None
    assert plan.state == "ENTRY_ACTIVATED"
    assert "5M_CLOSE_ABOVE_ZONE" in plan.entry_trigger_reason
    # structural values exist
    assert plan.sl is None or plan.sl > 0
    assert isinstance(plan.targets, list)


def test_sell_activated_close_below_zone() -> None:
    md = _base_md(ema9=100.5, ema21=100.0, vwap=100.2, close=99.0)
    # zone_low = 100.0, so close below => activated
    md["candles"]["5minute"][-1]["c"] = 99.0
    plan = build_execution_plan(decision="SELL", market_data=md)
    assert plan is not None
    assert plan.state == "ENTRY_ACTIVATED"
    assert "5M_CLOSE_BELOW_ZONE" in plan.entry_trigger_reason


def main() -> None:
    test_buy_waiting()
    test_buy_activated_close_above_zone()
    test_sell_activated_close_below_zone()
    print("entry_engine_selftest: OK")


if __name__ == "__main__":
    main()
