"""
Standardized Configuration Patterns for Kaizen Test Suite

This module provides unified configuration patterns, validation, and management
across all three test tiers, ensuring consistency and eliminating duplication.

Key Features:
- Standardized timeout values per tier
- Unified error handling patterns
- Centralized test data management
- Consistent mock strategies for unit tests
- Performance optimization patterns
"""

import os
import json
from typing import Dict, Any, List, Optional, Union, Type, Callable
from dataclasses import dataclass, asdict, field
from enum import Enum
from pathlib import Path

try:
    from kaizen.core.config import KaizenConfig
    KAIZEN_AVAILABLE = True
except ImportError:
    KAIZEN_AVAILABLE = False

try:
    import sys
    sys.path.append('/Users/esperie/repos/projects/kailash_python_sdk/tests/utils')
    from docker_config import (
        DATABASE_CONFIG, REDIS_CONFIG, MYSQL_CONFIG, OLLAMA_CONFIG
    )
    INFRASTRUCTURE_AVAILABLE = True
except ImportError:
    INFRASTRUCTURE_AVAILABLE = False


class ConfigurationTier(Enum):
    """Configuration tier with specific requirements."""
    UNIT = "unit"
    INTEGRATION = "integration"
    E2E = "e2e"


@dataclass
class StandardTimeout:
    """Standardized timeout configuration for all test operations."""
    # Core tier limits (milliseconds)
    unit_test_max_ms: int = 1000
    integration_test_max_ms: int = 5000
    e2e_test_max_ms: int = 10000

    # Framework operations
    framework_init_ms: int = 100
    agent_creation_ms: int = 200
    signature_creation_ms: int = 10
    workflow_compilation_ms: int = 200

    # Infrastructure operations
    database_connection_ms: int = 500
    redis_operation_ms: int = 50
    ollama_model_load_ms: int = 2000

    # Execution operations
    simple_execution_ms: int = 1000
    complex_execution_ms: int = 5000
    multi_agent_coordination_ms: int = 8000

    def get_tier_limit(self, tier: ConfigurationTier) -> int:
        """Get the maximum allowed time for a tier."""
        limits = {
            ConfigurationTier.UNIT: self.unit_test_max_ms,
            ConfigurationTier.INTEGRATION: self.integration_test_max_ms,
            ConfigurationTier.E2E: self.e2e_test_max_ms
        }
        return limits[tier]

    def to_seconds(self) -> 'StandardTimeout':
        """Convert all timeouts to seconds for easier use."""
        seconds_config = StandardTimeout()
        for field_name in asdict(self).keys():
            ms_value = getattr(self, field_name)
            if isinstance(ms_value, int):
                setattr(seconds_config, field_name.replace('_ms', '_seconds'), ms_value / 1000)
        return seconds_config


@dataclass
class StandardMemoryLimits:
    """Standardized memory limits for test tiers."""
    unit_test_mb: int = 50
    integration_test_mb: int = 200
    e2e_test_mb: int = 500

    # Component-specific limits
    framework_init_mb: int = 20
    agent_instance_mb: int = 10
    workflow_execution_mb: int = 100
    database_connection_pool_mb: int = 50

    def get_tier_limit(self, tier: ConfigurationTier) -> int:
        """Get memory limit for specific tier."""
        limits = {
            ConfigurationTier.UNIT: self.unit_test_mb,
            ConfigurationTier.INTEGRATION: self.integration_test_mb,
            ConfigurationTier.E2E: self.e2e_test_mb
        }
        return limits[tier]


@dataclass
class StandardAgentConfig:
    """Standardized agent configuration template."""
    model: str = "gpt-3.5-turbo"
    temperature: float = 0.7
    max_tokens: int = 1000
    timeout_seconds: int = 30
    retry_attempts: int = 3
    stream: bool = False

    # Tier-specific optimizations
    tier_optimizations: Dict[str, Dict[str, Any]] = field(default_factory=lambda: {
        "unit": {
            "timeout_seconds": 5,
            "max_tokens": 100,
            "retry_attempts": 1,
            "stream": False,
            "enable_caching": False
        },
        "integration": {
            "timeout_seconds": 15,
            "max_tokens": 500,
            "retry_attempts": 2,
            "stream": False,
            "enable_caching": True
        },
        "e2e": {
            "timeout_seconds": 30,
            "max_tokens": 2000,
            "retry_attempts": 3,
            "stream": False,
            "enable_caching": True,
            "enable_monitoring": True
        }
    })

    def for_tier(self, tier: ConfigurationTier) -> Dict[str, Any]:
        """Get agent config optimized for specific tier."""
        base_config = asdict(self)
        base_config.pop('tier_optimizations', None)

        tier_opts = self.tier_optimizations.get(tier.value, {})
        base_config.update(tier_opts)

        return base_config


@dataclass
class StandardKaizenConfig:
    """Standardized Kaizen configuration template."""
    debug: bool = True
    signature_validation: bool = True

    # Tier-specific configurations
    tier_configs: Dict[str, Dict[str, Any]] = field(default_factory=lambda: {
        "unit": {
            "memory_enabled": False,
            "optimization_enabled": False,
            "monitoring_enabled": False,
            "cache_enabled": False,
            "startup_timeout_seconds": 1,
            "max_concurrent_operations": 1,
            "lazy_loading": True
        },
        "integration": {
            "memory_enabled": True,
            "optimization_enabled": True,
            "monitoring_enabled": True,
            "cache_enabled": True,
            "startup_timeout_seconds": 5,
            "max_concurrent_operations": 3,
            "retry_attempts": 2,
            "health_check_interval_seconds": 10
        },
        "e2e": {
            "memory_enabled": True,
            "optimization_enabled": True,
            "monitoring_enabled": True,
            "cache_enabled": True,
            "audit_trail_enabled": True,
            "compliance_mode": "enterprise",
            "security_level": "high",
            "multi_agent_enabled": True,
            "startup_timeout_seconds": 10,
            "max_concurrent_operations": 5,
            "retry_attempts": 3,
            "enable_distributed_processing": True
        }
    })

    def for_tier(self, tier: ConfigurationTier) -> Dict[str, Any]:
        """Get Kaizen config for specific tier."""
        base_config = {
            "debug": self.debug,
            "signature_validation": self.signature_validation
        }

        tier_config = self.tier_configs.get(tier.value, {})
        base_config.update(tier_config)

        return base_config

    def to_kaizen_config(self, tier: ConfigurationTier) -> Optional['KaizenConfig']:
        """Convert to actual KaizenConfig instance if available."""
        if not KAIZEN_AVAILABLE:
            return None

        config_dict = self.for_tier(tier)
        return KaizenConfig(**config_dict)


@dataclass
class StandardTestData:
    """Standardized test data patterns."""
    # Simple test inputs
    simple_prompts: List[str] = field(default_factory=lambda: [
        "Hello, how are you?",
        "What is 2 + 2?",
        "Explain photosynthesis briefly.",
        "Generate a haiku about testing."
    ])

    # Complex test scenarios
    complex_scenarios: Dict[str, Any] = field(default_factory=lambda: {
        "data_analysis": {
            "input": {"data": [1, 2, 3, 4, 5], "operation": "statistics"},
            "expected_outputs": ["mean", "median", "std_dev"]
        },
        "multi_step_workflow": {
            "input": {"steps": ["validate", "transform", "analyze", "report"]},
            "expected_outputs": ["validation_result", "transformed_data", "analysis", "report"]
        }
    })

    # Error test cases
    error_scenarios: Dict[str, Any] = field(default_factory=lambda: {
        "invalid_input": {"input": None, "expected_error": "ValueError"},
        "timeout_scenario": {"input": {"delay": 10}, "expected_error": "TimeoutError"},
        "resource_exhaustion": {"input": {"size": 10**9}, "expected_error": "MemoryError"}
    })

    # Mock responses for unit tests
    mock_responses: Dict[str, Any] = field(default_factory=lambda: {
        "simple_qa": {
            "answer": "This is a mock response for testing",
            "confidence": 0.95,
            "metadata": {"model": "mock", "tokens": 10}
        },
        "analysis_result": {
            "analysis": {"findings": ["test finding 1", "test finding 2"]},
            "recommendations": ["recommendation 1", "recommendation 2"],
            "confidence": 0.87
        }
    })

    def get_tier_appropriate_data(self, tier: ConfigurationTier) -> Dict[str, Any]:
        """Get test data appropriate for tier."""
        if tier == ConfigurationTier.UNIT:
            return {
                "prompts": self.simple_prompts[:2],  # Fewer for speed
                "mock_responses": self.mock_responses,
                "allow_mocking": True
            }
        elif tier == ConfigurationTier.INTEGRATION:
            return {
                "prompts": self.simple_prompts,
                "scenarios": {k: v for k, v in self.complex_scenarios.items() if "simple" in k.lower()},
                "allow_mocking": False
            }
        else:  # E2E
            return {
                "prompts": self.simple_prompts,
                "scenarios": self.complex_scenarios,
                "error_scenarios": self.error_scenarios,
                "allow_mocking": False
            }


class StandardConfigurationManager:
    """Manages standardized configurations across test tiers."""

    def __init__(self):
        self.timeouts = StandardTimeout()
        self.memory_limits = StandardMemoryLimits()
        self.agent_config = StandardAgentConfig()
        self.kaizen_config = StandardKaizenConfig()
        self.test_data = StandardTestData()

    def get_tier_configuration(self, tier: ConfigurationTier) -> Dict[str, Any]:
        """Get complete configuration for a specific tier."""
        return {
            "tier": tier.value,
            "timeouts": {
                "max_test_time_ms": self.timeouts.get_tier_limit(tier),
                "framework_init_ms": self.timeouts.framework_init_ms,
                "agent_creation_ms": self.timeouts.agent_creation_ms,
                "database_connection_ms": self.timeouts.database_connection_ms
            },
            "memory_limits": {
                "max_memory_mb": self.memory_limits.get_tier_limit(tier),
                "framework_init_mb": self.memory_limits.framework_init_mb
            },
            "agent_config": self.agent_config.for_tier(tier),
            "kaizen_config": self.kaizen_config.for_tier(tier),
            "test_data": self.test_data.get_tier_appropriate_data(tier),
            "infrastructure_requirements": self._get_infrastructure_requirements(tier)
        }

    def _get_infrastructure_requirements(self, tier: ConfigurationTier) -> Dict[str, Any]:
        """Get infrastructure requirements for tier."""
        requirements = {
            ConfigurationTier.UNIT: {
                "required_services": [],
                "optional_services": [],
                "allow_mocking": True
            },
            ConfigurationTier.INTEGRATION: {
                "required_services": ["postgres", "redis"],
                "optional_services": ["mysql", "ollama"],
                "allow_mocking": False
            },
            ConfigurationTier.E2E: {
                "required_services": ["postgres", "redis"],
                "optional_services": ["mysql", "ollama"],
                "allow_mocking": False
            }
        }

        base_req = requirements[tier]

        if INFRASTRUCTURE_AVAILABLE:
            base_req["infrastructure_config"] = {
                "database": DATABASE_CONFIG,
                "redis": REDIS_CONFIG,
                "mysql": MYSQL_CONFIG,
                "ollama": OLLAMA_CONFIG
            }

        return base_req

    def validate_tier_configuration(self, tier: ConfigurationTier) -> List[str]:
        """Validate configuration for a tier and return any issues."""
        issues = []
        config = self.get_tier_configuration(tier)

        # Validate timeouts
        max_time = config["timeouts"]["max_test_time_ms"]
        if max_time <= 0:
            issues.append(f"Invalid max test time: {max_time}")

        # Validate memory limits
        max_memory = config["memory_limits"]["max_memory_mb"]
        if max_memory <= 0:
            issues.append(f"Invalid max memory: {max_memory}")

        # Validate agent config
        agent_config = config["agent_config"]
        if not agent_config.get("model"):
            issues.append("Missing model in agent config")

        temperature = agent_config.get("temperature", 0)
        if not (0 <= temperature <= 2):
            issues.append(f"Invalid temperature: {temperature}")

        # Validate infrastructure for non-unit tests
        if tier != ConfigurationTier.UNIT:
            infra = config["infrastructure_requirements"]
            if not INFRASTRUCTURE_AVAILABLE:
                issues.append("Infrastructure configuration not available for integration/e2e tests")

            for service in infra.get("required_services", []):
                # This would need actual service checks, but we'll keep it simple
                pass

        return issues

    def export_configuration(self, tier: ConfigurationTier, file_path: Optional[str] = None) -> str:
        """Export tier configuration to JSON format."""
        config = self.get_tier_configuration(tier)
        json_content = json.dumps(config, indent=2, default=str)

        if file_path:
            Path(file_path).write_text(json_content)

        return json_content

    def get_pytest_markers(self, tier: ConfigurationTier) -> List[str]:
        """Get appropriate pytest markers for tier."""
        markers = [tier.value]

        if tier == ConfigurationTier.UNIT:
            markers.extend(["fast", "isolated"])
        elif tier == ConfigurationTier.INTEGRATION:
            markers.extend(["requires_docker", "requires_postgres", "requires_redis", "no_mocking"])
        elif tier == ConfigurationTier.E2E:
            markers.extend(["requires_docker", "requires_postgres", "requires_redis", "no_mocking", "slow"])

        return markers

    def get_performance_assertions(self, tier: ConfigurationTier) -> Dict[str, Callable]:
        """Get performance assertion functions for tier."""
        max_time_ms = self.timeouts.get_tier_limit(tier)

        def assert_tier_performance(duration_ms: float, operation: str = "operation"):
            assert duration_ms <= max_time_ms, (
                f"Tier {tier.value} {operation} took {duration_ms:.2f}ms, "
                f"exceeding {tier.value} limit of {max_time_ms}ms"
            )

        def assert_memory_usage(memory_mb: float):
            max_memory = self.memory_limits.get_tier_limit(tier)
            assert memory_mb <= max_memory, (
                f"Tier {tier.value} used {memory_mb:.2f}MB, "
                f"exceeding {tier.value} limit of {max_memory}MB"
            )

        return {
            "assert_performance": assert_tier_performance,
            "assert_memory": assert_memory_usage
        }


# Global instance for easy access
standard_config = StandardConfigurationManager()


# ============================================================================
# UTILITY FUNCTIONS
# ============================================================================

def get_tier_config(tier: Union[str, ConfigurationTier]) -> Dict[str, Any]:
    """Get configuration for a tier (convenience function)."""
    if isinstance(tier, str):
        tier = ConfigurationTier(tier)
    return standard_config.get_tier_configuration(tier)


def validate_tier_setup(tier: Union[str, ConfigurationTier]) -> bool:
    """Validate that tier setup is correct."""
    if isinstance(tier, str):
        tier = ConfigurationTier(tier)

    issues = standard_config.validate_tier_configuration(tier)
    if issues:
        print(f"Tier {tier.value} validation issues:")
        for issue in issues:
            print(f"  - {issue}")
        return False

    return True


def get_standardized_timeouts() -> StandardTimeout:
    """Get standardized timeout configuration."""
    return standard_config.timeouts


def get_standardized_memory_limits() -> StandardMemoryLimits:
    """Get standardized memory limit configuration."""
    return standard_config.memory_limits


# Export main classes and functions
__all__ = [
    "ConfigurationTier", "StandardTimeout", "StandardMemoryLimits",
    "StandardAgentConfig", "StandardKaizenConfig", "StandardTestData",
    "StandardConfigurationManager", "standard_config", "get_tier_config",
    "validate_tier_setup", "get_standardized_timeouts", "get_standardized_memory_limits"
]