"""
Tests for SDK client.

Tests cover:
- Client initialization
- Configuration from arguments and environment
- Shutdown handling
- Exporter setup
"""

import os
import pytest
from unittest.mock import patch, MagicMock

from risicare import (
    init,
    shutdown,
    get_client,
    RisicareClient,
    RisicareConfig,
    _reset_client_for_testing,
)
from risicare_core import (
    is_executors_patched,
    is_asyncio_patched,
    _reset_context_for_testing,
)


# =============================================================================
# Fixtures
# =============================================================================

@pytest.fixture(autouse=True)
def reset_all():
    """Reset all state before and after each test."""
    _reset_context_for_testing()
    _reset_client_for_testing()
    yield
    _reset_context_for_testing()
    _reset_client_for_testing()


@pytest.fixture
def clean_env():
    """Clean environment of RISICARE_* variables."""
    old_env = {}
    for key in list(os.environ.keys()):
        if key.startswith("RISICARE_"):
            old_env[key] = os.environ.pop(key)
    yield
    os.environ.update(old_env)


# =============================================================================
# Client Initialization Tests
# =============================================================================

class TestClientInitialization:
    def test_init_returns_client(self, clean_env):
        """init() returns RisicareClient instance."""
        client = init()
        assert isinstance(client, RisicareClient)

    def test_init_singleton(self, clean_env):
        """init() returns same instance on repeated calls."""
        client1 = init()
        client2 = init()
        assert client1 is client2

    def test_get_client_before_init(self, clean_env):
        """get_client() returns None before init."""
        assert get_client() is None

    def test_get_client_after_init(self, clean_env):
        """get_client() returns client after init."""
        init()
        assert get_client() is not None

    def test_init_with_api_key(self, clean_env):
        """init() with api_key configures HTTP exporter."""
        client = init(api_key="rsk-test-key")
        assert client.config.api_key == "rsk-test-key"

    def test_init_with_environment(self, clean_env):
        """init() accepts environment parameter."""
        client = init(environment="production")
        assert client.config.environment == "production"


# =============================================================================
# Configuration Tests
# =============================================================================

class TestConfiguration:
    def test_default_configuration(self, clean_env):
        """Default configuration values are correct."""
        client = init()
        config = client.config

        assert config.endpoint == "https://app.risicare.ai"
        assert config.environment == "development"
        assert config.enabled is True
        assert config.trace_content is True
        assert config.sample_rate == 1.0
        assert config.batch_size == 100
        assert config.batch_timeout_ms == 1000
        assert config.auto_patch is True
        assert config.debug is False

    def test_config_from_env_vars(self):
        """Configuration reads from environment variables."""
        with patch.dict(os.environ, {
            "RISICARE_API_KEY": "rsk-env-key",
            "RISICARE_ENVIRONMENT": "staging",
            "RISICARE_TRACING": "true",
            "RISICARE_DEBUG": "true",
        }):
            _reset_client_for_testing()
            client = init()

            assert client.config.api_key == "rsk-env-key"
            assert client.config.environment == "staging"
            assert client.config.enabled is True
            assert client.config.debug is True

    def test_args_override_env_vars(self):
        """Arguments override environment variables."""
        with patch.dict(os.environ, {
            "RISICARE_ENVIRONMENT": "staging",
        }):
            _reset_client_for_testing()
            client = init(environment="production")

            assert client.config.environment == "production"

    def test_sample_rate_clamped(self, clean_env):
        """sample_rate is clamped to 0.0-1.0."""
        client = init(sample_rate=2.0)
        assert client.config.sample_rate == 1.0

        _reset_client_for_testing()
        client = init(sample_rate=-0.5)
        assert client.config.sample_rate == 0.0


# =============================================================================
# Auto-Patching Tests
# =============================================================================

class TestAutoPatching:
    def test_auto_patch_enabled_by_default(self, clean_env):
        """auto_patch is enabled by default."""
        init()
        assert is_executors_patched()
        assert is_asyncio_patched()

    def test_auto_patch_can_be_disabled(self, clean_env):
        """auto_patch can be disabled."""
        init(auto_patch=False)
        # Note: patching state depends on previous tests,
        # but the client config should reflect the setting
        client = get_client()
        assert client.config.auto_patch is False


# =============================================================================
# Shutdown Tests
# =============================================================================

class TestShutdown:
    def test_shutdown_clears_client(self, clean_env):
        """shutdown() clears the global client."""
        init()
        assert get_client() is not None

        shutdown()
        assert get_client() is None

    def test_shutdown_is_safe_without_init(self, clean_env):
        """shutdown() is safe to call without init."""
        shutdown()  # Should not raise

    def test_shutdown_multiple_times_safe(self, clean_env):
        """shutdown() can be called multiple times safely."""
        init()
        shutdown()
        shutdown()  # Should not raise
        shutdown()  # Should not raise

    def test_can_reinitialize_after_shutdown(self, clean_env):
        """Can call init() again after shutdown()."""
        client1 = init()
        shutdown()

        client2 = init()
        assert client2 is not None
        # Should be different instances after shutdown
        # (though implementation may vary)


# =============================================================================
# Exporter Tests
# =============================================================================

class TestExporters:
    def test_no_exporters_without_api_key(self, clean_env):
        """No HTTP exporter without API key."""
        client = init()
        # With no API key, no HTTP exporter should be added
        # (though console exporter may be added in debug mode)
        assert client.config.api_key is None

    def test_debug_mode_adds_console_exporter(self, clean_env):
        """Debug mode adds console exporter."""
        client = init(debug=True)
        assert client.config.debug is True
        # Console exporter should be present
        # (verified by checking exporter list contains ConsoleExporter)
        exporter_types = [type(e).__name__ for e in client._exporters]
        assert "ConsoleExporter" in exporter_types


# =============================================================================
# RisicareConfig Tests
# =============================================================================

class TestRisicareConfig:
    def test_config_defaults(self):
        """RisicareConfig has correct defaults."""
        config = RisicareConfig()

        assert config.api_key is None
        assert config.endpoint == "https://app.risicare.ai"
        assert config.enabled is True
        assert config.sample_rate == 1.0

    def test_config_custom_values(self):
        """RisicareConfig accepts custom values."""
        config = RisicareConfig(
            api_key="rsk-custom",
            endpoint="https://custom.endpoint",
            environment="testing",
            sample_rate=0.5,
        )

        assert config.api_key == "rsk-custom"
        assert config.endpoint == "https://custom.endpoint"
        assert config.environment == "testing"
        assert config.sample_rate == 0.5
