"""Swing Trading Agent tests."""
from app.agents.swing import RSI_LOW, RSI_HIGH, STOP_ATR_MULT, SwingTradingAgent
from app.agents.risk_manager import RiskManagerAgent
from app.services.market_data import MockMarketDataProvider

provider = MockMarketDataProvider()
agent = SwingTradingAgent()


def _uptrend_bars(n: int = 70) -> list[dict]:
    """Synthetic clean uptrend with a recent pullback toward EMA21."""
    bars = []
    price = 100.0
    for i in range(n):
        price *= 1.008  # steady rise
        bars.append({"date": f"d{i}", "open": price * 0.995, "high": price * 1.01,
                     "low": price * 0.99, "close": round(price, 2),
                     "volume": 1_000_000})
    # pullback: last 3 bars drift down ~3%
    for j in range(3):
        price *= 0.99
        bars.append({"date": f"p{j}", "open": price * 1.002, "high": price * 1.008,
                     "low": price * 0.992, "close": round(price, 2), "volume": 1_200_000})
    return bars


def test_uptrend_pullback_produces_buy():
    result = agent.run({"history": _uptrend_bars()})
    assert result.direction == "BUY"
    assert result.score > 0
    assert result.data["stop_atr_mult"] == STOP_ATR_MULT


def test_downtrend_produces_sell():
    bars = _uptrend_bars()
    # mirror into a downtrend
    flipped = []
    for b in bars:
        flipped.append({**b, "close": round(220 - b["close"], 2),
                        "high": round(220 - b["low"], 2), "low": round(220 - b["high"], 2),
                        "open": round(220 - b["open"], 2)})
    result = agent.run({"history": flipped})
    assert result.direction == "SELL"


def test_choppy_market_scores_below_gate():
    from app.agents.swing import MIN_SWING_SCORE

    bars = []
    for i in range(70):
        price = 100 + (3 if i % 2 == 0 else -3)
        bars.append({"date": f"c{i}", "open": price, "high": price + 2,
                     "low": price - 2, "close": price, "volume": 1_000_000})
    result = agent.run({"history": bars})
    # Chop may register weak structure, but must never clear the signal gate
    assert result.score < MIN_SWING_SCORE


def test_risk_manager_handles_buy_sell_directions():
    quote = provider.get_quote("TSLA")
    for direction, expect_stop_below in (("BUY", True), ("SELL", False)):
        r = RiskManagerAgent().run({
            "quote": quote, "direction": direction, "atr": 5.0, "atr_mult": STOP_ATR_MULT,
            "confidence": 80.0, "probability": 60.0, "open_risk_usd": 0.0,
        })
        d = r.data
        if expect_stop_below:
            assert d["stop_loss"] < d["entry"] < d["target1"]
        else:
            assert d["target1"] < d["entry"] < d["stop_loss"]
        # 2x ATR stop distance honored
        assert abs(abs(d["entry"] - d["stop_loss"]) - STOP_ATR_MULT * 5.0) < 0.01


def test_pipeline_creates_swing_signals():
    from fastapi.testclient import TestClient
    from app.main import app

    client = TestClient(app)
    client.post("/api/scanner/run")
    signals = client.get("/api/signals").json()
    types = {s["signal_type"] for s in signals}
    assert "options" in types
    swing = [s for s in signals if s["signal_type"] == "swing"]
    for s in swing:
        assert s["direction"] in ("BUY", "SELL")
        assert s["option_contract"] == {}
