"""Unit tests for the Fireplace SDK using respx to mock HTTP."""

import pytest
import respx
import httpx

from fireplace_gg import (
    Fireplace,
    AuthenticationError,
    BadRequestError,
    RateLimitError,
    ServerError,
)

BASE = "https://data.fireplace.gg/api/v1/external"


def _fp() -> Fireplace:
    return Fireplace(api_key="fp_pk_test", api_secret="fp_sk_test")


@respx.mock
def test_get_market_by_id():
    respx.get(f"{BASE}/market/get-market-by-id", params={"id": "12345"}).mock(
        return_value=httpx.Response(200, json={"success": True, "data": {"id": "12345", "question": "Test?"}})
    )
    fp = _fp()
    result = fp.markets.get_by_id("12345")
    assert result["id"] == "12345"
    fp.close()


@respx.mock
def test_get_event_by_id():
    respx.get(f"{BASE}/market/get-event-by-id").mock(
        return_value=httpx.Response(200, json={"success": True, "data": {"id": "ev1", "markets": []}})
    )
    fp = _fp()
    result = fp.markets.get_event_by_id("ev1", show_active=True)
    assert result["id"] == "ev1"
    fp.close()


@respx.mock
def test_latest_candles_list():
    respx.get(f"{BASE}/market/latest-candles").mock(
        return_value=httpx.Response(200, json={"success": True, "data": [{"t": 1}]})
    )
    fp = _fp()
    result = fp.markets.latest_candles(["m1", "m2"])
    assert isinstance(result, list)
    fp.close()


@respx.mock
def test_historical_candles():
    respx.get(f"{BASE}/market/historical-candles-v2").mock(
        return_value=httpx.Response(200, json={"success": True, "data": []})
    )
    fp = _fp()
    fp.markets.historical_candles("m1", interval="1h", include_orderbook=True, limit=100)
    req = respx.calls.last.request
    assert "interval=1h" in str(req.url)
    assert "include_orderbook=true" in str(req.url)
    fp.close()


@respx.mock
def test_recent_trades():
    respx.get(f"{BASE}/market/recent-trades").mock(
        return_value=httpx.Response(200, json={"success": True, "data": {"trades": []}})
    )
    fp = _fp()
    result = fp.markets.recent_trades("m1", side="BUY", limit=10)
    assert "trades" in result
    fp.close()


@respx.mock
def test_orderbook():
    respx.get(f"{BASE}/market/orderbook").mock(
        return_value=httpx.Response(200, json={"success": True, "data": {"bids": [], "asks": []}})
    )
    fp = _fp()
    result = fp.markets.orderbook("m1")
    assert "bids" in result
    fp.close()


@respx.mock
def test_top_positions():
    respx.get(f"{BASE}/market/top-positions").mock(
        return_value=httpx.Response(200, json={"success": True, "data": []})
    )
    fp = _fp()
    fp.markets.top_positions("m1", limit=10, amount="1k")
    req = respx.calls.last.request
    assert "amount=1k" in str(req.url)
    fp.close()


@respx.mock
def test_wallet_trades():
    respx.get(f"{BASE}/wallets/trades").mock(
        return_value=httpx.Response(200, json={"success": True, "data": {"trades": [], "hasMore": False}})
    )
    fp = _fp()
    result = fp.wallets.trades(["0xabc", "0xdef"], side="BUY")
    assert "trades" in result
    fp.close()


@respx.mock
def test_wallet_net_flows():
    respx.get(f"{BASE}/wallets/net-flows").mock(
        return_value=httpx.Response(200, json={"success": True, "data": {"flows": []}})
    )
    fp = _fp()
    result = fp.wallets.net_flows("0xabc", lookback="7d", sort_by="netFlows")
    assert "flows" in result
    fp.close()


@respx.mock
def test_profile_overview():
    respx.get(f"{BASE}/profile/overview").mock(
        return_value=httpx.Response(200, json={"success": True, "data": {"pnl": 100}})
    )
    fp = _fp()
    result = fp.profiles.overview("0xabc")
    assert result["pnl"] == 100
    fp.close()


@respx.mock
def test_leaderboard_get():
    respx.get(f"{BASE}/leaderboard/leaderboard").mock(
        return_value=httpx.Response(200, json={"success": True, "data": []})
    )
    fp = _fp()
    fp.leaderboard.get(timeframe="7d", sort_by="total_pnl", limit=25)
    req = respx.calls.last.request
    assert "timeframe=7d" in str(req.url)
    fp.close()


@respx.mock
def test_search_events():
    respx.get(f"{BASE}/search/search-events").mock(
        return_value=httpx.Response(200, json={"success": True, "data": []})
    )
    fp = _fp()
    fp.search.events(q="Bitcoin", limit=5, status="active")
    req = respx.calls.last.request
    assert "q=Bitcoin" in str(req.url)
    fp.close()


@respx.mock
def test_auth_error():
    respx.get(f"{BASE}/market/get-market-by-id").mock(
        return_value=httpx.Response(401, json={"success": False, "message": "Invalid API key"})
    )
    fp = _fp()
    with pytest.raises(AuthenticationError, match="Invalid API key"):
        fp.markets.get_by_id("12345")
    fp.close()


@respx.mock
def test_rate_limit():
    respx.get(f"{BASE}/market/get-market-by-id").mock(
        return_value=httpx.Response(429, json={"success": False, "message": "Rate limit exceeded"},
                                     headers={"X-RateLimit-Reset": "9999999999"})
    )
    fp = _fp()
    with pytest.raises(RateLimitError) as exc_info:
        fp.markets.get_by_id("12345")
    assert exc_info.value.retry_after is not None
    fp.close()


@respx.mock
def test_server_error():
    respx.get(f"{BASE}/market/get-market-by-id").mock(
        return_value=httpx.Response(500, json={"success": False, "message": "Internal error"})
    )
    fp = _fp()
    with pytest.raises(ServerError):
        fp.markets.get_by_id("12345")
    fp.close()


def test_missing_keys():
    with pytest.raises(ValueError, match="Both api_key and api_secret"):
        Fireplace()


@respx.mock
def test_rate_limit_headers():
    respx.get(f"{BASE}/market/get-market-by-id").mock(
        return_value=httpx.Response(200, json={"success": True, "data": {}},
                                     headers={"X-RateLimit-Limit": "5", "X-RateLimit-Remaining": "3", "X-RateLimit-Reset": "1710000005"})
    )
    fp = _fp()
    fp.markets.get_by_id("12345")
    assert fp.rate_limit == 5
    assert fp.rate_remaining == 3
    fp.close()


@respx.mock
def test_none_params_stripped():
    respx.get(f"{BASE}/market/recent-trades").mock(
        return_value=httpx.Response(200, json={"success": True, "data": {"trades": []}})
    )
    fp = _fp()
    fp.markets.recent_trades("m1")
    url = str(respx.calls.last.request.url)
    assert "cursor" not in url
    assert "side" not in url
    fp.close()
