"""Tests for STRIGIVAL SDK Client."""

import pytest
from unittest.mock import AsyncMock, patch, MagicMock
from strigival import StrigivalClient
from strigival.types import Strategy, StrategyPerformance
from strigival.exceptions import StrigivalAPIError, AuthenticationError


class TestStrigivalClient:
    """Tests for StrigivalClient."""
    
    def test_client_initialization(self):
        """Test client initializes with correct defaults."""
        client = StrigivalClient(base_url="https://api.strigival.io")
        assert client.base_url == "https://api.strigival.io"
        assert client._session is None
    
    def test_client_initialization_with_api_key(self):
        """Test client initializes with API key."""
        client = StrigivalClient(
            base_url="https://api.strigival.io",
            api_key="test-api-key"
        )
        assert client._api_key == "test-api-key"
    
    def test_client_initialization_invalid_url(self):
        """Test client raises error for invalid URL."""
        with pytest.raises(ValueError):
            StrigivalClient(base_url="")


class TestStrategyMethods:
    """Tests for strategy-related methods."""
    
    @pytest.fixture
    def client(self):
        return StrigivalClient(base_url="https://api.strigival.io")
    
    @pytest.fixture
    def mock_strategy_response(self):
        return {
            "id": 1,
            "name": "Alpha Momentum",
            "trader_address": "0x1234567890abcdef",
            "vault_address": "0xabcdef1234567890",
            "tvl": 1000000.0,
            "apy": 0.25,
            "sharpe_ratio": 2.1,
            "max_drawdown": -0.08,
            "is_active": True,
        }
    
    @pytest.mark.asyncio
    async def test_get_strategies(self, client, mock_strategy_response):
        """Test fetching strategies list."""
        with patch.object(client, '_request', new_callable=AsyncMock) as mock_request:
            mock_request.return_value = {"strategies": [mock_strategy_response]}
            
            strategies = await client.get_strategies()
            
            assert len(strategies) == 1
            mock_request.assert_called_once()
    
    @pytest.mark.asyncio
    async def test_get_strategy_by_id(self, client, mock_strategy_response):
        """Test fetching single strategy by ID."""
        with patch.object(client, '_request', new_callable=AsyncMock) as mock_request:
            mock_request.return_value = mock_strategy_response
            
            strategy = await client.get_strategy(1)
            
            assert strategy["id"] == 1
            assert strategy["name"] == "Alpha Momentum"


class TestAuthenticationMethods:
    """Tests for authentication methods."""
    
    @pytest.fixture
    def client(self):
        return StrigivalClient(base_url="https://api.strigival.io")
    
    @pytest.mark.asyncio
    async def test_get_nonce(self, client):
        """Test getting authentication nonce."""
        with patch.object(client, '_request', new_callable=AsyncMock) as mock_request:
            mock_request.return_value = {"nonce": "abc123", "expires_at": 1234567890}
            
            result = await client.get_nonce("0x1234567890abcdef")
            
            assert result["nonce"] == "abc123"
    
    @pytest.mark.asyncio
    async def test_authenticate_invalid_signature(self, client):
        """Test authentication with invalid signature raises error."""
        with patch.object(client, '_request', new_callable=AsyncMock) as mock_request:
            mock_request.side_effect = StrigivalAPIError("Invalid signature", 401)
            
            with pytest.raises(StrigivalAPIError):
                await client.authenticate("0x1234", "invalid_sig")


class TestErrorHandling:
    """Tests for error handling."""
    
    @pytest.fixture
    def client(self):
        return StrigivalClient(base_url="https://api.strigival.io")
    
    @pytest.mark.asyncio
    async def test_api_error_handling(self, client):
        """Test API error is properly raised."""
        with patch.object(client, '_request', new_callable=AsyncMock) as mock_request:
            mock_request.side_effect = StrigivalAPIError("Not found", 404)
            
            with pytest.raises(StrigivalAPIError) as exc_info:
                await client.get_strategy(999)
            
            assert exc_info.value.status_code == 404
    
    @pytest.mark.asyncio
    async def test_authentication_error(self, client):
        """Test authentication error is properly raised."""
        with patch.object(client, '_request', new_callable=AsyncMock) as mock_request:
            mock_request.side_effect = AuthenticationError("Token expired")
            
            with pytest.raises(AuthenticationError):
                await client.get_strategies()


class TestTypes:
    """Tests for type definitions."""
    
    def test_strategy_performance_creation(self):
        """Test StrategyPerformance dataclass creation."""
        perf = StrategyPerformance(
            sharpe_ratio=2.1,
            total_return=0.35,
            annual_return=0.28,
            max_drawdown=-0.08,
            volatility=0.15,
            return_1d=0.005,
            return_7d=0.02,
            return_30d=0.08,
        )
        
        assert perf.sharpe_ratio == 2.1
        assert perf.max_drawdown == -0.08
