"""
Unit tests for KaizenConfig enterprise parameter support.

This module tests the foundational configuration system that enables all
advanced Kaizen features including signature programming, MCP integration,
transparency, and enterprise compliance.

CRITICAL: These tests define the exact requirements for unblocking
BLOCKER-001 and must pass before any implementation changes.
"""

import os
import tempfile
from unittest.mock import patch
import pytest
from typing import Dict, Any

from kaizen.core.config import KaizenConfig
from kaizen.core.framework import Kaizen


class TestKaizenConfigParameterSupport:
    """Test core parameter validation and handling."""

    def test_enterprise_parameter_support(self):
        """Test all required enterprise parameters are supported."""
        enterprise_config = {
            'signature_programming_enabled': True,
            'mcp_integration': {'enabled': True, 'port': 8080},
            'multi_agent_enabled': True,
            'transparency_enabled': True,
            'audit_trail_enabled': True,
            'compliance_mode': 'enterprise',
            'security_level': 'high',
            'memory_enabled': True,
            'optimization_enabled': False,
            'monitoring_level': 'detailed'
        }

        # This should not raise an exception
        config = KaizenConfig(**enterprise_config)

        # Verify all parameters are set correctly
        assert config.signature_programming_enabled == True
        assert config.mcp_integration == {'enabled': True, 'port': 8080}
        assert config.multi_agent_enabled == True
        assert config.transparency_enabled == True
        assert config.audit_trail_enabled == True
        assert config.compliance_mode == 'enterprise'
        assert config.security_level == 'high'
        assert config.memory_enabled == True
        assert config.optimization_enabled == False
        assert config.monitoring_level == 'detailed'

    def test_minimal_configuration(self):
        """Test basic configuration with defaults."""
        config = KaizenConfig()

        # Test essential defaults
        assert config.signature_programming_enabled == False  # Conservative default
        assert config.mcp_integration == {}  # Empty dict default
        assert config.multi_agent_enabled == False
        assert config.transparency_enabled == False
        assert config.audit_trail_enabled == False
        assert config.compliance_mode == 'standard'
        assert config.security_level == 'standard'
        assert config.memory_enabled == False
        assert config.optimization_enabled == False
        assert config.monitoring_level == 'basic'

    def test_progressive_configuration(self):
        """Test incremental feature enablement."""
        # Start with basic config
        config = KaizenConfig(
            signature_programming_enabled=True
        )
        assert config.signature_programming_enabled == True
        assert config.mcp_integration == {}  # Still default

        # Add MCP integration
        config = KaizenConfig(
            signature_programming_enabled=True,
            mcp_integration={'enabled': True}
        )
        assert config.signature_programming_enabled == True
        assert config.mcp_integration == {'enabled': True}

    def test_development_vs_production_profiles(self):
        """Test different configuration profiles."""
        # Development profile
        dev_config = KaizenConfig(
            debug=True,
            monitoring_level='detailed',
            security_level='standard'
        )
        assert dev_config.debug == True
        assert dev_config.monitoring_level == 'detailed'
        assert dev_config.security_level == 'standard'

        # Production profile
        prod_config = KaizenConfig(
            debug=False,
            monitoring_level='basic',
            security_level='high',
            audit_trail_enabled=True,
            transparency_enabled=True,
            compliance_mode='enterprise'
        )
        assert prod_config.debug == False
        assert prod_config.monitoring_level == 'basic'
        assert prod_config.security_level == 'high'
        assert prod_config.audit_trail_enabled == True
        assert prod_config.compliance_mode == 'enterprise'

    def test_mcp_integration_configuration(self):
        """Test MCP integration parameter handling."""
        # Basic MCP config
        config = KaizenConfig(
            mcp_integration={'enabled': True}
        )
        assert config.mcp_integration['enabled'] == True

        # Advanced MCP config
        advanced_mcp = {
            'enabled': True,
            'port': 8080,
            'server_config': {
                'name': 'kaizen-server',
                'version': '1.0.0'
            },
            'client_configs': [
                {'name': 'client1', 'endpoint': 'http://localhost:8081'}
            ]
        }
        config = KaizenConfig(mcp_integration=advanced_mcp)
        assert config.mcp_integration == advanced_mcp

    def test_signature_programming_configuration(self):
        """Test signature programming parameter."""
        # Disabled by default
        config = KaizenConfig()
        assert config.signature_programming_enabled == False

        # Explicitly enabled
        config = KaizenConfig(signature_programming_enabled=True)
        assert config.signature_programming_enabled == True

        # Test with additional signature config
        config = KaizenConfig(
            signature_programming_enabled=True,
            signature_validation_strict=True,  # Future parameter
            signature_auto_generation=False    # Future parameter
        )
        assert config.signature_programming_enabled == True


class TestKaizenConfigValidation:
    """Test parameter validation and error handling."""

    def test_invalid_compliance_mode(self):
        """Test validation of compliance mode values."""
        with pytest.raises(ValueError, match="Invalid compliance_mode"):
            KaizenConfig(compliance_mode='invalid_mode')

    def test_invalid_security_level(self):
        """Test validation of security level values."""
        with pytest.raises(ValueError, match="Invalid security_level"):
            KaizenConfig(security_level='invalid_level')

    def test_invalid_monitoring_level(self):
        """Test validation of monitoring level values."""
        with pytest.raises(ValueError, match="Invalid monitoring_level"):
            KaizenConfig(monitoring_level='invalid_level')

    def test_mcp_integration_validation(self):
        """Test MCP integration parameter validation."""
        # Must be dict if provided
        with pytest.raises(TypeError, match="mcp_integration must be a dict"):
            KaizenConfig(mcp_integration="not_a_dict")

        # Empty dict is valid
        config = KaizenConfig(mcp_integration={})
        assert config.mcp_integration == {}

    def test_boolean_parameter_validation(self):
        """Test boolean parameter type validation."""
        bool_params = [
            'signature_programming_enabled',
            'multi_agent_enabled',
            'transparency_enabled',
            'audit_trail_enabled',
            'memory_enabled',
            'optimization_enabled'
        ]

        for param in bool_params:
            # Test valid boolean
            config = KaizenConfig(**{param: True})
            assert getattr(config, param) == True

            # Test invalid type
            with pytest.raises(TypeError, match=f"{param} must be a boolean"):
                KaizenConfig(**{param: "not_boolean"})

    def test_conflicting_configurations(self):
        """Test detection of conflicting configuration options."""
        # High security should require audit trails
        with pytest.raises(ValueError, match="High security level requires audit trails"):
            KaizenConfig(
                security_level='high',
                audit_trail_enabled=False
            )

        # Enterprise compliance should require transparency
        with pytest.raises(ValueError, match="Enterprise compliance requires transparency"):
            KaizenConfig(
                compliance_mode='enterprise',
                transparency_enabled=False
            )


class TestKaizenConfigEnvironmentVariables:
    """Test environment variable configuration support."""

    def test_environment_variable_override(self):
        """Test configuration from environment variables."""
        env_vars = {
            'KAIZEN_SIGNATURE_PROGRAMMING_ENABLED': 'true',
            'KAIZEN_MCP_INTEGRATION_ENABLED': 'true',
            'KAIZEN_TRANSPARENCY_ENABLED': 'true',
            'KAIZEN_AUDIT_TRAIL_ENABLED': 'true',  # Required for high security and enterprise compliance
            'KAIZEN_COMPLIANCE_MODE': 'enterprise',
            'KAIZEN_SECURITY_LEVEL': 'high'
        }

        with patch.dict(os.environ, env_vars):
            config = KaizenConfig.from_environment()

            assert config.signature_programming_enabled == True
            assert config.transparency_enabled == True
            assert config.audit_trail_enabled == True
            assert config.compliance_mode == 'enterprise'
            assert config.security_level == 'high'

    def test_environment_variable_types(self):
        """Test proper type conversion from environment variables."""
        with patch.dict(os.environ, {
            'KAIZEN_SIGNATURE_PROGRAMMING_ENABLED': 'false',
            'KAIZEN_MEMORY_ENABLED': 'true',
            'KAIZEN_MONITORING_LEVEL': 'detailed'
        }):
            config = KaizenConfig.from_environment()

            assert config.signature_programming_enabled == False  # Boolean
            assert config.memory_enabled == True  # Boolean
            assert config.monitoring_level == 'detailed'  # String

    def test_environment_variable_precedence(self):
        """Test environment variables override defaults but not explicit params."""
        with patch.dict(os.environ, {
            'KAIZEN_SIGNATURE_PROGRAMMING_ENABLED': 'true'
        }):
            # Environment variable should override default
            config = KaizenConfig.from_environment()
            assert config.signature_programming_enabled == True

            # Explicit parameter should override environment variable
            config = KaizenConfig.from_environment(signature_programming_enabled=False)
            assert config.signature_programming_enabled == False


class TestKaizenConfigFileLoading:
    """Test configuration file loading support."""

    def test_yaml_configuration_loading(self):
        """Test loading configuration from YAML file."""
        yaml_content = """
signature_programming_enabled: true
mcp_integration:
  enabled: true
  port: 8080
transparency_enabled: true
audit_trail_enabled: true
compliance_mode: enterprise
security_level: high
"""

        with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
            f.write(yaml_content)
            f.flush()

            config = KaizenConfig.from_file(f.name)

            assert config.signature_programming_enabled == True
            assert config.mcp_integration == {'enabled': True, 'port': 8080}
            assert config.transparency_enabled == True
            assert config.compliance_mode == 'enterprise'
            assert config.security_level == 'high'

        os.unlink(f.name)

    def test_json_configuration_loading(self):
        """Test loading configuration from JSON file."""
        json_content = """{
    "signature_programming_enabled": true,
    "mcp_integration": {
        "enabled": true,
        "port": 8080
    },
    "transparency_enabled": true,
    "compliance_mode": "enterprise"
}"""

        with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
            f.write(json_content)
            f.flush()

            config = KaizenConfig.from_file(f.name)

            assert config.signature_programming_enabled == True
            assert config.mcp_integration == {'enabled': True, 'port': 8080}
            assert config.transparency_enabled == True
            assert config.compliance_mode == 'enterprise'

        os.unlink(f.name)

    def test_configuration_file_validation(self):
        """Test validation when loading from files."""
        invalid_json = """{
    "compliance_mode": "invalid_mode"
}"""

        with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
            f.write(invalid_json)
            f.flush()

            with pytest.raises(ValueError, match="Invalid compliance_mode"):
                KaizenConfig.from_file(f.name)

        os.unlink(f.name)


class TestKaizenConfigPersistence:
    """Test configuration saving and loading."""

    def test_configuration_serialization(self):
        """Test config can be serialized and deserialized."""
        original_config = KaizenConfig(
            signature_programming_enabled=True,
            mcp_integration={'enabled': True, 'port': 8080},
            transparency_enabled=True,
            compliance_mode='enterprise'
        )

        # Serialize to dict
        config_dict = original_config.to_dict()

        # Recreate from dict
        restored_config = KaizenConfig.from_dict(config_dict)

        # Verify all parameters match
        assert restored_config.signature_programming_enabled == original_config.signature_programming_enabled
        assert restored_config.mcp_integration == original_config.mcp_integration
        assert restored_config.transparency_enabled == original_config.transparency_enabled
        assert restored_config.compliance_mode == original_config.compliance_mode

    def test_configuration_save_load(self):
        """Test saving and loading configuration to/from file."""
        config = KaizenConfig(
            signature_programming_enabled=True,
            transparency_enabled=True,
            compliance_mode='enterprise'
        )

        with tempfile.NamedTemporaryFile(suffix='.yaml', delete=False) as f:
            # Save configuration
            config.save(f.name)

            # Load configuration
            loaded_config = KaizenConfig.load(f.name)

            # Verify parameters match
            assert loaded_config.signature_programming_enabled == config.signature_programming_enabled
            assert loaded_config.transparency_enabled == config.transparency_enabled
            assert loaded_config.compliance_mode == config.compliance_mode

        os.unlink(f.name)


class TestKaizenFrameworkConfigIntegration:
    """Test Kaizen framework integration with enterprise configuration."""

    def test_dict_config_backward_compatibility(self):
        """Test Kaizen() with dict config (backward compatibility)."""
        config_dict = {
            'signature_programming_enabled': True,
            'mcp_integration': {'enabled': True},
            'transparency_enabled': True,
            'memory_enabled': True
        }

        # This is the pattern that currently fails - must work after implementation
        kaizen = Kaizen(config=config_dict)

        # Verify config is properly handled
        assert hasattr(kaizen, '_config')
        assert kaizen._config.signature_programming_enabled == True
        assert kaizen._config.mcp_integration == {'enabled': True}
        assert kaizen._config.transparency_enabled == True
        assert kaizen._config.memory_enabled == True

    def test_kaizen_config_object_integration(self):
        """Test Kaizen() with KaizenConfig object."""
        config = KaizenConfig(
            signature_programming_enabled=True,
            mcp_integration={'enabled': True, 'port': 8080},
            transparency_enabled=True,
            audit_trail_enabled=True
        )

        kaizen = Kaizen(config=config)

        # Verify config object is stored properly
        assert kaizen._config == config
        assert kaizen._config.signature_programming_enabled == True
        assert kaizen._config.mcp_integration == {'enabled': True, 'port': 8080}

    def test_mixed_parameter_integration(self):
        """Test Kaizen() with both config dict and individual parameters."""
        config_dict = {
            'signature_programming_enabled': True,
            'mcp_integration': {'enabled': True}
        }

        # Config dict should take precedence over individual parameters
        kaizen = Kaizen(
            config=config_dict,
            memory_enabled=False,  # This should be overridden by config
            debug=True  # This should be used since not in config
        )

        # Verify proper precedence
        assert kaizen._config.signature_programming_enabled == True  # From config dict
        assert kaizen._config.mcp_integration == {'enabled': True}  # From config dict
        assert kaizen.debug == True  # From individual parameter

    def test_performance_requirements(self):
        """Test configuration loading performance requirements."""
        import time

        # Large enterprise configuration
        enterprise_config = {
            'signature_programming_enabled': True,
            'mcp_integration': {
                'enabled': True,
                'port': 8080,
                'server_config': {'name': 'kaizen-server', 'version': '1.0.0'},
                'client_configs': [
                    {'name': f'client{i}', 'endpoint': f'http://localhost:808{i}'}
                    for i in range(10)
                ]
            },
            'transparency_enabled': True,
            'audit_trail_enabled': True,
            'compliance_mode': 'enterprise',
            'security_level': 'high',
            'monitoring_level': 'detailed'
        }

        # Test configuration creation performance (<10ms)
        start_time = time.time()
        config = KaizenConfig(**enterprise_config)
        config_time = (time.time() - start_time) * 1000

        assert config_time < 10, f"Configuration creation took {config_time:.2f}ms, should be <10ms"

        # Test framework initialization performance
        start_time = time.time()
        kaizen = Kaizen(config=config)
        init_time = (time.time() - start_time) * 1000

        # Framework init can be slower but should be reasonable
        assert init_time < 100, f"Framework initialization took {init_time:.2f}ms, should be <100ms"