"""
Tests for ZeroDBClient
"""

import pytest
from unittest.mock import MagicMock
from zerodb_mcp import ZeroDBClient
from zerodb_mcp.exceptions import (
    AuthenticationError,
    RateLimitError,
    ValidationError,
    ZeroDBError
)


class TestZeroDBClient:
    """Test ZeroDBClient initialization and core methods"""

    def test_init_with_api_key(self):
        """Test client initialization with API key"""
        client = ZeroDBClient(api_key="test_key")
        assert client.auth.api_key == "test_key"
        assert client.auth.auth_type == "api_key"

    def test_init_with_jwt_token(self):
        """Test client initialization with JWT token"""
        client = ZeroDBClient(jwt_token="test_token")
        assert client.auth.jwt_token == "test_token"
        assert client.auth.auth_type == "jwt"

    def test_init_without_credentials(self):
        """Test client initialization without credentials raises error"""
        with pytest.raises(ValueError, match="Either api_key or jwt_token"):
            ZeroDBClient()

    def test_init_with_custom_config(self):
        """Test client initialization with custom configuration"""
        client = ZeroDBClient(
            api_key="test_key",
            base_url="https://custom.api.com",
            timeout=60.0,
            max_retries=5,
            retry_delay=2.0
        )
        assert client.base_url == "https://custom.api.com"
        assert client.timeout == 60.0
        assert client.max_retries == 5
        assert client.retry_delay == 2.0

    @pytest.mark.asyncio
    async def test_execute_success(self, client, mock_httpx_client):
        """Test successful operation execution"""
        # Mock successful response
        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_response.json.return_value = {"status": "success", "vector_id": "123"}
        mock_httpx_client.post.return_value = mock_response

        result = await client.execute("upsert_vector", {"test": "data"})

        assert result["status"] == "success"
        assert result["vector_id"] == "123"
        mock_httpx_client.post.assert_called_once()

    @pytest.mark.asyncio
    async def test_execute_authentication_error(self, client, mock_httpx_client):
        """Test authentication error handling"""
        mock_response = MagicMock()
        mock_response.status_code = 401
        mock_response.json.return_value = {"detail": "Invalid credentials"}
        mock_httpx_client.post.return_value = mock_response

        with pytest.raises(AuthenticationError):
            await client.execute("upsert_vector", {})

    @pytest.mark.asyncio
    async def test_execute_rate_limit_error(self, client, mock_httpx_client):
        """Test rate limit error handling"""
        mock_response = MagicMock()
        mock_response.status_code = 429
        mock_response.headers = {"Retry-After": "60"}
        mock_response.json.return_value = {"detail": "Rate limit exceeded"}
        mock_httpx_client.post.return_value = mock_response

        with pytest.raises(RateLimitError) as exc_info:
            await client.execute("upsert_vector", {}, retry=False)

        assert exc_info.value.retry_after == 60

    @pytest.mark.asyncio
    async def test_execute_validation_error(self, client, mock_httpx_client):
        """Test validation error handling"""
        mock_response = MagicMock()
        mock_response.status_code = 422
        mock_response.json.return_value = {
            "detail": [
                {"loc": ["embedding"], "msg": "Field required"}
            ]
        }
        mock_httpx_client.post.return_value = mock_response

        with pytest.raises(ValidationError):
            await client.execute("upsert_vector", {}, retry=False)

    @pytest.mark.asyncio
    async def test_health_check(self, client, mock_httpx_client):
        """Test health check endpoint"""
        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_response.json.return_value = {"status": "healthy", "version": "1.0.0"}
        mock_response.raise_for_status = MagicMock()
        mock_httpx_client.get.return_value = mock_response

        health = await client.health_check()

        assert health["status"] == "healthy"
        assert health["version"] == "1.0.0"

    @pytest.mark.asyncio
    async def test_context_manager(self, monkeypatch):
        """Test async context manager"""
        monkeypatch.setenv("ZERODB_API_KEY", "test_key")

        async with ZeroDBClient() as client:
            assert client is not None

        # Client should be closed after exiting context

    def test_repr(self, client):
        """Test string representation"""
        repr_str = repr(client)
        assert "ZeroDBClient" in repr_str
        assert "auth_type" in repr_str
