"""
Unit tests for Bybit provider — raw JSON → domain event parsing.
"""
import pytest

from app.domain.events import EventType
from app.providers.bybit import BybitProvider


@pytest.fixture
def provider():
    return BybitProvider()


# ── Trade parsing ──────────────────────────────────────────────────────


def test_parse_trade_basic(provider):
    """Basic publicTrade parsing."""
    raw = {
        "topic": "publicTrade.BTCUSDT",
        "data": [
            {
                "s": "BTCUSDT",
                "S": "Buy",
                "v": "0.001",
                "p": "70500.5",
                "T": 1672515782136,
                "i": "trade123",
            }
        ],
    }
    event = provider._parse(raw)
    assert event is not None
    assert event.event_type == EventType.TRADE
    assert event.symbol == "BTCUSDT"
    assert event.price == 70500.5
    assert event.size == 0.001
    assert event.side == "buy"
    assert event.trade_id == "trade123"
    assert event.provider == "bybit"


def test_parse_trade_sell_side(provider):
    """Sell side trade."""
    raw = {
        "topic": "publicTrade.ETHUSDT",
        "data": [
            {
                "s": "ETHUSDT",
                "S": "Sell",
                "v": "10.5",
                "p": "2100.00",
                "T": 1672515782136,
                "i": "t456",
            }
        ],
    }
    event = provider._parse(raw)
    assert event.side == "sell"
    assert event.symbol == "ETHUSDT"


def test_parse_trade_batch_takes_last(provider):
    """Multiple trades in a batch — takes the last one."""
    raw = {
        "topic": "publicTrade.BTCUSDT",
        "data": [
            {"s": "BTCUSDT", "S": "Buy", "v": "0.001", "p": "70000.0", "T": 100, "i": "first"},
            {"s": "BTCUSDT", "S": "Sell", "v": "0.01", "p": "70100.0", "T": 200, "i": "last"},
        ],
    }
    event = provider._parse(raw)
    assert event.trade_id == "last"
    assert event.price == 70100.0


def test_parse_trade_timestamp(provider):
    """Exchange timestamp is correctly parsed."""
    raw = {
        "topic": "publicTrade.BTCUSDT",
        "data": [
            {"s": "BTCUSDT", "S": "Buy", "v": "1", "p": "70000", "T": 1672515782136, "i": "x"},
        ],
    }
    event = provider._parse(raw)
    assert event.ts_exchange is not None
    assert event.ts_exchange.year >= 2022


# ── Ticker (quote) parsing ─────────────────────────────────────────────


def test_parse_ticker_basic(provider):
    """Bybit tickers → QuoteEvent."""
    raw = {
        "topic": "tickers.BTCUSDT",
        "data": {
            "symbol": "BTCUSDT",
            "bid1Price": "70000.5",
            "bid1Size": "1.5",
            "ask1Price": "70001.0",
            "ask1Size": "2.0",
            "ts": "1672515782136",
        },
    }
    event = provider._parse(raw)
    assert event is not None
    assert event.event_type == EventType.QUOTE
    assert event.symbol == "BTCUSDT"
    assert event.bid == 70000.5
    assert event.ask == 70001.0
    assert event.bid_size == 1.5
    assert event.ask_size == 2.0
    assert event.provider == "bybit"


def test_parse_ticker_missing_bid(provider):
    """Ticker without bid → returns None."""
    raw = {
        "topic": "tickers.BTCUSDT",
        "data": {"symbol": "BTCUSDT"},
    }
    event = provider._parse(raw)
    assert event is None


# ── Edge cases ─────────────────────────────────────────────────────────


def test_parse_unknown_topic(provider):
    """Unknown topic → None."""
    raw = {"topic": "some_unknown.BTCUSDT", "data": {}}
    event = provider._parse(raw)
    assert event is None


def test_parse_pong_skipped(provider):
    """Pong/subscribe messages are not events."""
    raw = {"op": "pong", "success": True}
    # _parse would not be called for op messages (handled in stream()),
    # but let's verify _parse returns None for incomplete data
    event = provider._parse(raw)
    assert event is None


def test_parse_empty_trade_data(provider):
    """Empty trade data array → None."""
    raw = {"topic": "publicTrade.BTCUSDT", "data": []}
    event = provider._parse(raw)
    assert event is None
