"""Unit tests for CoinGecko pricing provider."""

import pytest
from unittest.mock import Mock, patch, MagicMock
from decimal import Decimal
import httpx

from src.data.providers.coingecko_provider import CoinGeckoProvider


@pytest.fixture
def provider():
    """Create a CoinGecko provider instance."""
    return CoinGeckoProvider()


@pytest.fixture
def mock_response():
    """Create a mock HTTP response."""
    response = Mock()
    response.status_code = 200
    response.json = Mock(return_value={
        'bitcoin': {
            'usd': 50000.0,
            'usd_24h_change': 2.5,
            'usd_24h_vol': 1000000.0,
        }
    })
    return response


class TestCoinGeckoProvider:
    """Tests for CoinGeckoProvider."""
    
    def test_init(self, provider):
        """Test provider initialization."""
        assert provider.name == "CoinGecko"
        assert not provider.supports_websocket
        assert not provider._connected
    
    @patch('src.data.providers.coingecko_provider.httpx.Client')
    def test_connect_success(self, mock_client_class, provider, mock_response):
        """Test successful connection."""
        mock_client = Mock()
        mock_client.get = Mock(return_value=mock_response)
        mock_client_class.return_value = mock_client
        
        result = provider.connect()
        
        assert result is True
        assert provider._connected is True
    
    @patch('src.data.providers.coingecko_provider.httpx.Client')
    def test_connect_failure(self, mock_client_class, provider):
        """Test connection failure."""
        mock_client = Mock()
        mock_client.get = Mock(side_effect=Exception("Connection failed"))
        mock_client_class.return_value = mock_client
        
        result = provider.connect()
        
        assert result is False
        assert not provider._connected
    
    def test_parse_symbol(self, provider):
        """Test symbol parsing."""
        coin_id, currency = provider._parse_symbol('BTC/USD')
        assert coin_id == 'bitcoin'
        assert currency == 'usd'
        
        coin_id, currency = provider._parse_symbol('ETH/USDT')
        assert coin_id == 'ethereum'
        assert currency == 'usd'  # USDT maps to USD
    
    @patch('src.data.providers.coingecko_provider.httpx.Client')
    def test_get_ticker(self, mock_client_class, provider, mock_response):
        """Test getting ticker data."""
        mock_client = Mock()
        mock_client.get = Mock(return_value=mock_response)
        mock_client_class.return_value = mock_client
        provider.connect()
        
        ticker = provider.get_ticker('BTC/USD')
        
        assert ticker['symbol'] == 'BTC/USD'
        assert isinstance(ticker['last'], Decimal)
        assert ticker['last'] > 0
        assert 'timestamp' in ticker
    
    @patch('src.data.providers.coingecko_provider.httpx.Client')
    def test_get_ohlcv(self, mock_client_class, provider):
        """Test getting OHLCV data."""
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json = Mock(return_value=[
            [1609459200000, 50000, 51000, 49000, 50000],
        ])
        
        mock_client = Mock()
        mock_client.get = Mock(return_value=mock_response)
        mock_client_class.return_value = mock_client
        provider.connect()
        
        ohlcv = provider.get_ohlcv('BTC/USD', '1h', limit=10)
        
        assert len(ohlcv) > 0
        # CoinGecko returns 5 elements, we add volume as 0
        assert len(ohlcv[0]) == 6
    
    def test_normalize_symbol(self, provider):
        """Test symbol normalization."""
        normalized = provider.normalize_symbol('btc-usdt')
        assert normalized == 'BTC/USDT'
