"""
Tests for the edm_client module.
"""

import pytest
from unittest.mock import Mock, patch, MagicMock
import pandas as pd
import json

# Add src to path for imports
import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src'))

from edm_client import EdmClient, EdmConfig
from edm_client.exceptions import EdmConnectionError, EdmApiError, EdmTimeoutError


class TestEdmConfig:
    """Tests for EdmConfig dataclass."""

    def test_default_config(self):
        """Test default configuration values."""
        config = EdmConfig()
        assert config.rest_url == "http://localhost:8080"
        assert config.ws_url == "ws://localhost:8765"
        assert config.timeout == 30.0
        assert config.enabled is True

    def test_custom_config(self):
        """Test custom configuration values."""
        config = EdmConfig(
            rest_url="http://custom:9000",
            ws_url="ws://custom:9001",
            timeout=60.0,
            enabled=False
        )
        assert config.rest_url == "http://custom:9000"
        assert config.ws_url == "ws://custom:9001"
        assert config.timeout == 60.0
        assert config.enabled is False


class TestEdmClient:
    """Tests for EdmClient REST client."""

    def test_init_default(self):
        """Test client initialization with defaults."""
        client = EdmClient()
        assert client.base_url == "http://localhost:8080"
        assert client.timeout == 30.0

    def test_init_with_config(self):
        """Test client initialization with EdmConfig."""
        config = EdmConfig(rest_url="http://custom:9000", timeout=45.0)
        client = EdmClient(config=config)
        assert client.base_url == "http://custom:9000"
        assert client.timeout == 45.0

    def test_init_with_url(self):
        """Test client initialization with URL parameter."""
        client = EdmClient(base_url="http://example.com:8080/", timeout=60.0)
        assert client.base_url == "http://example.com:8080"  # trailing slash removed
        assert client.timeout == 60.0

    @patch('edm_client.client.requests.get')
    def test_get_candles_sync_success(self, mock_get):
        """Test successful candle fetch."""
        # Mock response
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = {
            'candles': [
                {'time': 1700000000000, 'open': 100.0, 'high': 105.0, 'low': 99.0, 'close': 104.0, 'volume': 1000.0},
                {'time': 1700003600000, 'open': 104.0, 'high': 108.0, 'low': 103.0, 'close': 107.0, 'volume': 1200.0},
            ]
        }
        mock_get.return_value = mock_response

        client = EdmClient()
        df = client.get_candles_sync(
            exchange='binance',
            symbol='BTC/USDT',
            timeframe='1h',
            limit=100
        )

        assert isinstance(df, pd.DataFrame)
        assert len(df) == 2
        assert list(df.columns) == ['time', 'open', 'high', 'low', 'close', 'volume']
        assert df.iloc[0]['time'] == 1700000000000
        assert df.iloc[0]['close'] == 104.0

    @patch('edm_client.client.requests.get')
    def test_get_candles_sync_empty(self, mock_get):
        """Test empty candle response."""
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = {'candles': []}
        mock_get.return_value = mock_response

        client = EdmClient()
        df = client.get_candles_sync(
            exchange='binance',
            symbol='BTC/USDT',
            timeframe='1h'
        )

        assert isinstance(df, pd.DataFrame)
        assert len(df) == 0
        assert list(df.columns) == ['time', 'open', 'high', 'low', 'close', 'volume']

    @patch('edm_client.client.requests.get')
    def test_get_candles_sync_api_error(self, mock_get):
        """Test API error handling."""
        mock_response = Mock()
        mock_response.status_code = 500
        mock_response.text = "Internal Server Error"
        mock_get.return_value = mock_response

        client = EdmClient()
        with pytest.raises(EdmApiError) as exc_info:
            client.get_candles_sync(
                exchange='binance',
                symbol='BTC/USDT',
                timeframe='1h'
            )

        assert exc_info.value.status_code == 500

    @patch('edm_client.client.requests.get')
    def test_get_candles_sync_connection_error(self, mock_get):
        """Test connection error handling."""
        import requests
        mock_get.side_effect = requests.exceptions.ConnectionError("Connection refused")

        client = EdmClient()
        with pytest.raises(EdmConnectionError):
            client.get_candles_sync(
                exchange='binance',
                symbol='BTC/USDT',
                timeframe='1h'
            )

    @patch('edm_client.client.requests.get')
    def test_get_candles_sync_timeout(self, mock_get):
        """Test timeout error handling."""
        import requests
        mock_get.side_effect = requests.exceptions.Timeout("Request timed out")

        client = EdmClient()
        with pytest.raises(EdmTimeoutError):
            client.get_candles_sync(
                exchange='binance',
                symbol='BTC/USDT',
                timeframe='1h'
            )

    @patch('edm_client.client.requests.get')
    def test_get_exchanges_sync(self, mock_get):
        """Test get_exchanges_sync method."""
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = {'exchanges': ['binance', 'kucoin', 'kraken']}
        mock_get.return_value = mock_response

        client = EdmClient()
        exchanges = client.get_exchanges_sync()

        assert exchanges == ['binance', 'kucoin', 'kraken']

    @patch('edm_client.client.requests.get')
    def test_get_symbols_sync(self, mock_get):
        """Test get_symbols_sync method."""
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = {'symbols': ['BTC/USDT', 'ETH/USDT', 'SOL/USDT']}
        mock_get.return_value = mock_response

        client = EdmClient()
        symbols = client.get_symbols_sync('binance')

        assert symbols == ['BTC/USDT', 'ETH/USDT', 'SOL/USDT']

    @patch('edm_client.client.requests.get')
    def test_health_check_sync_healthy(self, mock_get):
        """Test health check when service is healthy."""
        mock_response = Mock()
        mock_response.status_code = 200
        mock_get.return_value = mock_response

        client = EdmClient()
        assert client.health_check_sync() is True

    @patch('edm_client.client.requests.get')
    def test_health_check_sync_unhealthy(self, mock_get):
        """Test health check when service is unavailable."""
        mock_response = Mock()
        mock_response.status_code = 503
        mock_get.return_value = mock_response

        client = EdmClient()
        assert client.health_check_sync() is False

    @patch('edm_client.client.requests.get')
    def test_health_check_sync_connection_error(self, mock_get):
        """Test health check when connection fails."""
        import requests
        mock_get.side_effect = requests.exceptions.ConnectionError()

        client = EdmClient()
        assert client.health_check_sync() is False


class TestEdmClientUrlBuilding:
    """Tests for URL construction in EdmClient."""

    @patch('edm_client.client.requests.get')
    def test_url_with_all_params(self, mock_get):
        """Test URL construction with all parameters."""
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = {'candles': []}
        mock_get.return_value = mock_response

        from datetime import datetime
        client = EdmClient(base_url="http://test:8080")
        client.get_candles_sync(
            exchange='binance',
            symbol='BTC/USDT',
            timeframe='1h',
            start=datetime(2024, 1, 1),
            end=datetime(2024, 1, 2),
            limit=100
        )

        # Verify the URL was constructed correctly
        call_args = mock_get.call_args
        url = call_args[0][0]
        assert 'exchange=binance' in url
        assert 'symbol=BTC%2FUSDT' in url  # URL encoded /
        assert 'timeframe=1h' in url
        assert 'limit=100' in url
        assert 'start=' in url
        assert 'end=' in url


if __name__ == '__main__':
    pytest.main([__file__, '-v'])
