from __future__ import annotations

import datetime as dt
from types import SimpleNamespace

import pytest

from apps.web.routers import orb_trading
from libs.oracle_client.alpaca import AlpacaSnapshot


class _FakeORBState:
    def __init__(self, positions: list[SimpleNamespace]) -> None:
        self._positions = positions

    def get_session(self, session_id: str) -> SimpleNamespace | None:
        return SimpleNamespace(session_id=session_id, session_name="test")

    def get_open_positions(self, session_id: str, date: str) -> list[SimpleNamespace]:
        assert date == dt.date.today().isoformat()
        return self._positions


def _position(
    ticker: str,
    *,
    direction: str,
    entry_price: float,
    shares: int = 2,
) -> SimpleNamespace:
    return SimpleNamespace(
        ticker=ticker,
        direction=direction,
        entry_price=entry_price,
        entry_time="2026-05-04T09:59:00-04:00",
        shares=shares,
        current_stop=entry_price * 0.95,
        peak_price=entry_price,
        trailing_active=False,
        atr_at_entry=1.0,
        stop_distance=5.0,
        rvol=1.0,
        composite_score=0.5,
    )


def test_orb_positions_change_pct_is_position_return_not_day_change(monkeypatch: pytest.MonkeyPatch) -> None:
    positions = [
        _position("LONG", direction="long", entry_price=100.0),
        _position("SHORT", direction="short", entry_price=100.0),
    ]
    monkeypatch.setattr(orb_trading, "_state", lambda: _FakeORBState(positions))

    def fake_snapshots(tickers: list[str]) -> dict[str, AlpacaSnapshot]:
        assert tickers == ["LONG", "SHORT"]
        return {
            # Positive day change must not make a losing long look profitable.
            "LONG": AlpacaSnapshot(ticker="LONG", price=95.0, change_pct=12.34),
            # Negative day change must not make a winning short look losing.
            "SHORT": AlpacaSnapshot(ticker="SHORT", price=95.0, change_pct=-7.89),
        }

    monkeypatch.setattr("libs.oracle_client.alpaca.get_snapshots", fake_snapshots)

    result = orb_trading.get_positions("session-1")
    by_ticker = {p["ticker"]: p for p in result["positions"]}

    assert by_ticker["LONG"]["current_price"] == pytest.approx(95.0)
    assert by_ticker["LONG"]["change_pct"] == pytest.approx(-5.0)
    assert by_ticker["LONG"]["unrealized_pnl"] == pytest.approx(-10.0)
    assert by_ticker["LONG"]["day_change_pct"] == pytest.approx(12.34)

    assert by_ticker["SHORT"]["current_price"] == pytest.approx(95.0)
    assert by_ticker["SHORT"]["change_pct"] == pytest.approx(5.0)
    assert by_ticker["SHORT"]["unrealized_pnl"] == pytest.approx(10.0)
    assert by_ticker["SHORT"]["day_change_pct"] == pytest.approx(-7.89)
