"""Tests for market discovery (mocked HTTP)."""

import json
from unittest.mock import patch, MagicMock

import pytest
import requests
from horizon.discovery import discover_markets, _discover_polymarket, _discover_kalshi
from horizon._horizon import Market


def _mock_polymarket_response():
    return [
        {
            "slug": "will-btc-hit-100k",
            "question": "Will BTC hit $100k?",
            "tokens": [
                {"outcome": "Yes", "token_id": "tok_yes_1"},
                {"outcome": "No", "token_id": "tok_no_1"},
            ],
            "condition_id": "cond_1",
            "neg_risk": False,
            "volume": 50000,
            "active": True,
            "end_date_iso": "2030-12-31T00:00:00Z",
        },
        {
            "slug": "will-eth-merge",
            "question": "Will ETH merge?",
            "tokens": [
                {"outcome": "Yes", "token_id": "tok_yes_2"},
                {"outcome": "No", "token_id": "tok_no_2"},
            ],
            "condition_id": "cond_2",
            "neg_risk": True,
            "volume": 100,
            "active": True,
        },
    ]


def _mock_kalshi_response():
    return {
        "markets": [
            {
                "ticker": "BTC-100K",
                "title": "Bitcoin above $100k?",
                "status": "open",
                "expiration_time": "2030-12-31T00:00:00Z",
            },
            {
                "ticker": "RAIN-NYC",
                "title": "Will it rain in NYC?",
                "status": "open",
            },
        ]
    }


class TestDiscoverPolymarket:
    @patch("horizon.discovery.requests.get")
    def test_basic_discovery(self, mock_get):
        mock_resp = MagicMock()
        mock_resp.ok = True
        mock_resp.raise_for_status = MagicMock()
        mock_resp.json.return_value = _mock_polymarket_response()
        mock_get.return_value = mock_resp

        # query="btc" matches only the BTC market (client-side text filter)
        markets = discover_markets(exchange="polymarket", query="btc")
        assert len(markets) == 1
        assert markets[0].exchange == "polymarket"
        assert markets[0].slug == "will-btc-hit-100k"
        assert markets[0].yes_token_id == "tok_yes_1"

    @patch("horizon.discovery.requests.get")
    def test_no_query_returns_all(self, mock_get):
        mock_resp = MagicMock()
        mock_resp.ok = True
        mock_resp.raise_for_status = MagicMock()
        mock_resp.json.return_value = _mock_polymarket_response()
        mock_get.return_value = mock_resp

        markets = discover_markets(exchange="polymarket")
        assert len(markets) == 2

    @patch("horizon.discovery.requests.get")
    def test_volume_filter(self, mock_get):
        mock_resp = MagicMock()
        mock_resp.ok = True
        mock_resp.raise_for_status = MagicMock()
        mock_resp.json.return_value = _mock_polymarket_response()
        mock_get.return_value = mock_resp

        markets = discover_markets(exchange="polymarket", min_volume=1000)
        assert len(markets) == 1
        assert markets[0].slug == "will-btc-hit-100k"

    @patch("horizon.discovery.requests.get")
    def test_limit(self, mock_get):
        mock_resp = MagicMock()
        mock_resp.ok = True
        mock_resp.raise_for_status = MagicMock()
        mock_resp.json.return_value = _mock_polymarket_response()
        mock_get.return_value = mock_resp

        markets = discover_markets(exchange="polymarket", limit=1)
        assert len(markets) == 1

    @patch("horizon.discovery.requests.get")
    def test_network_error(self, mock_get):
        mock_get.side_effect = requests.RequestException("Network error")
        markets = discover_markets(exchange="polymarket")
        assert markets == []


class TestDiscoverKalshi:
    @patch("horizon.discovery.requests.get")
    def test_basic_discovery(self, mock_get):
        mock_resp = MagicMock()
        mock_resp.ok = True
        mock_resp.raise_for_status = MagicMock()
        mock_resp.json.return_value = _mock_kalshi_response()
        mock_get.return_value = mock_resp

        # query="btc" matches only the BTC market (client-side text filter)
        markets = discover_markets(exchange="kalshi", query="btc")
        assert len(markets) == 1
        assert markets[0].exchange == "kalshi"
        assert markets[0].ticker == "BTC-100K"

    @patch("horizon.discovery.requests.get")
    def test_no_query_returns_all(self, mock_get):
        mock_resp = MagicMock()
        mock_resp.ok = True
        mock_resp.raise_for_status = MagicMock()
        mock_resp.json.return_value = _mock_kalshi_response()
        mock_get.return_value = mock_resp

        markets = discover_markets(exchange="kalshi")
        assert len(markets) == 2

    @patch("horizon.discovery.requests.get")
    def test_limit(self, mock_get):
        mock_resp = MagicMock()
        mock_resp.ok = True
        mock_resp.raise_for_status = MagicMock()
        mock_resp.json.return_value = _mock_kalshi_response()
        mock_get.return_value = mock_resp

        markets = discover_markets(exchange="kalshi", limit=1)
        assert len(markets) == 1

    @patch("horizon.discovery.requests.get")
    def test_network_error(self, mock_get):
        mock_get.side_effect = requests.RequestException("Network error")
        markets = discover_markets(exchange="kalshi")
        assert markets == []


class TestDiscoverValidation:
    def test_unknown_exchange(self):
        with pytest.raises(ValueError, match="Unknown exchange"):
            discover_markets(exchange="binance")
