"""
Tests for configuration system
"""
import os
import pytest
import tempfile
from unittest.mock import patch
from src.config import Config, get_config, reload_config, validate_required_config


class TestConfig:
    """Test cases for configuration system"""
    
    def test_config_defaults(self):
        """Test default configuration values"""
        with patch.dict(os.environ, {"BACKEND_URL": "http://test.com"}, clear=True):
            config = Config()
            
            assert config.udp_host == "0.0.0.0"
            assert config.udp_port == 9000
            assert config.driver == "file"
            assert config.log_level == "INFO"
            assert config.storage_backend == "memory"
            assert config.api_host == "0.0.0.0"
            assert config.api_port == 8000
            assert config.backend_url == "http://test.com"
    
    def test_config_from_env_vars(self):
        """Test configuration from environment variables"""
        env_vars = {
            "UDP_HOST": "192.168.1.100",
            "UDP_PORT": "9001", 
            "BACKEND_URL": "http://backend.example.com",
            "DRIVER": "console",
            "LOG_LEVEL": "DEBUG",
            "STORAGE_BACKEND": "redis",
            "API_PORT": "8080"
        }
        
        with patch.dict(os.environ, env_vars, clear=True):
            config = Config()
            
            assert config.udp_host == "192.168.1.100"
            assert config.udp_port == 9001
            assert config.backend_url == "http://backend.example.com"
            assert config.driver == "console"
            assert config.log_level == "DEBUG"
            assert config.storage_backend == "redis"
            assert config.api_port == 8080
    
    def test_config_from_dotenv_file(self):
        """Test configuration from .env file"""
        env_content = """
UDP_HOST=10.0.0.1
UDP_PORT=9002
BACKEND_URL=http://dotenv.example.com
DRIVER=null
LOG_LEVEL=WARNING
"""
        
        with tempfile.NamedTemporaryFile(mode='w', suffix='.env', delete=False) as f:
            f.write(env_content)
            env_file = f.name
        
        try:
            with patch.dict(os.environ, {}, clear=True):
                config = Config(_env_file=env_file)
                
                assert config.udp_host == "10.0.0.1"
                assert config.udp_port == 9002
                assert config.backend_url == "http://dotenv.example.com"
                assert config.driver == "null"
                assert config.log_level == "WARNING"
        finally:
            os.unlink(env_file)
    
    def test_env_vars_override_dotenv(self):
        """Test that environment variables override .env file"""
        env_content = """
UDP_HOST=10.0.0.1
BACKEND_URL=http://dotenv.example.com
DRIVER=null
"""
        
        with tempfile.NamedTemporaryFile(mode='w', suffix='.env', delete=False) as f:
            f.write(env_content)
            env_file = f.name
        
        try:
            env_vars = {
                "UDP_HOST": "127.0.0.1",  # This should override .env
                "DRIVER": "console"       # This should override .env
            }
            
            with patch.dict(os.environ, env_vars, clear=True):
                config = Config(_env_file=env_file)
                
                assert config.udp_host == "127.0.0.1"  # From env var
                assert config.driver == "console"      # From env var
                assert config.backend_url == "http://dotenv.example.com"  # From .env
        finally:
            os.unlink(env_file)
    
    def test_missing_required_config(self):
        """Test that missing required config raises error"""
        from pydantic_core import ValidationError
        
        with patch.dict(os.environ, {}, clear=True):
            with pytest.raises(ValidationError, match="backend_url"):
                Config()
    
    def test_invalid_port_validation(self):
        """Test port validation"""
        from pydantic_core import ValidationError
        
        with patch.dict(os.environ, {"BACKEND_URL": "http://test.com", "UDP_PORT": "70000"}, clear=True):
            with pytest.raises(ValidationError, match="Port must be between"):
                Config()
        
        with patch.dict(os.environ, {"BACKEND_URL": "http://test.com", "UDP_PORT": "0"}, clear=True):
            with pytest.raises(ValidationError, match="Port must be between"):
                Config()
    
    def test_invalid_driver_validation(self):
        """Test driver validation"""
        from pydantic_core import ValidationError
        
        with patch.dict(os.environ, {"BACKEND_URL": "http://test.com", "DRIVER": "invalid"}, clear=True):
            with pytest.raises(ValidationError, match="Driver must be one of"):
                Config()
    
    def test_invalid_log_level_validation(self):
        """Test log level validation"""
        from pydantic_core import ValidationError
        
        with patch.dict(os.environ, {"BACKEND_URL": "http://test.com", "LOG_LEVEL": "INVALID"}, clear=True):
            with pytest.raises(ValidationError, match="Log level must be one of"):
                Config()
    
    def test_invalid_storage_backend_validation(self):
        """Test storage backend validation"""
        from pydantic_core import ValidationError
        
        with patch.dict(os.environ, {"BACKEND_URL": "http://test.com", "STORAGE_BACKEND": "invalid"}, clear=True):
            with pytest.raises(ValidationError, match="Storage backend must be one of"):
                Config()
    
    def test_case_insensitive_log_level(self):
        """Test that log level is case insensitive"""
        with patch.dict(os.environ, {"BACKEND_URL": "http://test.com", "LOG_LEVEL": "debug"}, clear=True):
            config = Config()
            assert config.log_level == "DEBUG"
    
    def test_get_config_singleton(self):
        """Test that get_config returns singleton"""
        with patch.dict(os.environ, {"BACKEND_URL": "http://test.com"}, clear=True):
            # Clear any existing config
            import src.config
            src.config._config = None
            
            config1 = get_config()
            config2 = get_config()
            
            assert config1 is config2
    
    def test_reload_config(self):
        """Test configuration reload"""
        with patch.dict(os.environ, {"BACKEND_URL": "http://test.com", "UDP_PORT": "9000"}, clear=True):
            # Clear any existing config
            import src.config
            src.config._config = None
            
            config1 = get_config()
            assert config1.udp_port == 9000
            
            # Change environment and reload
            with patch.dict(os.environ, {"UDP_PORT": "9001"}):
                config2 = reload_config()
                assert config2.udp_port == 9001
                assert config1 is not config2
    
    def test_validate_required_config_success(self):
        """Test successful configuration validation"""
        with patch.dict(os.environ, {"BACKEND_URL": "http://test.com"}, clear=True):
            # Clear any existing config
            import src.config
            src.config._config = None
            
            # Should not raise any exception
            result = validate_required_config()
            assert result is True
    
    def test_validate_required_config_failure(self):
        """Test configuration validation failure"""
        with patch.dict(os.environ, {}, clear=True):
            # Clear any existing config
            import src.config
            src.config._config = None
            
            with pytest.raises(RuntimeError, match="Configuration validation failed"):
                validate_required_config()


if __name__ == "__main__":
    pytest.main([__file__])
