"""
IICY Configuration System

This module provides the configuration system for the iicy framework.
Users can create a .iicy/config.py file to customize behavior.
"""

import os
from pathlib import Path
from typing import Dict, Any, Optional, Callable
from functools import lru_cache
from pydantic import BaseModel, Field


class LambdaConfig(BaseModel):
    """Configuration for Lambda functions."""
    timeout: int = Field(default=3, description="Default timeout for Lambda functions")
    memory: int = Field(default=128, description="Default memory for Lambda functions")
    runtime: str = Field(default="python3.11", description="Default runtime for Lambda functions")
    custom_naming_function: Optional[Callable] = Field(default=None, description="Custom naming function")

class IICYConfigModel(BaseModel):
    """Pydantic model for IICY configuration."""
    lambda_: LambdaConfig = Field(default_factory=LambdaConfig, alias="lambda", description="Lambda configuration")
    template_format_version: str = Field(default="2010-09-09", description="CloudFormation template format version")
    default_stack_name: str = Field(default="IICYStack", description="Default CloudFormation stack name")


def _load_config():
    """Load configuration from .iicy/config.py if it exists."""
    # Look for .iicy/config.py in current directory and parent directories
    current_dir = Path.cwd()
    
    for path in [current_dir] + list(current_dir.parents):
        config_file = path / '.iicy' / 'config.py'
        if config_file.exists():
            try:
                # Import the config module
                import sys
                import importlib.util
                
                spec = importlib.util.spec_from_file_location("iicy_config", config_file)
                config_module = importlib.util.module_from_spec(spec)
                spec.loader.exec_module(config_module)
                
                # Execute the config module to populate our global _iicy_config
                _execute_config_module(config_module)
                break
                
            except Exception as e:
                print(f"Warning: Could not load config from {config_file}: {e}")
                continue

def _execute_config_module(module):
    """Execute the config module to populate our global configuration."""
    try:
        # Import our configuration functions into the module's namespace
        from .config import configure, naming_strategy
        
        # Add our functions to the module's namespace
        module.configure = configure
        module.naming_strategy = naming_strategy
        
        # Execute the module to populate configuration
        # Read the source file and execute it
        if hasattr(module, '__file__'):
            with open(module.__file__, 'r') as f:
                source = f.read()
            exec(source, module.__dict__)
        
        # The configuration functions have already updated our global _iicy_config
        
    except Exception as e:
        print(f"Warning: Could not execute configuration module: {e}")

# Configuration will be loaded when first accessed
_config_loaded = False

def get_config():
    """Get the configuration object, loading it if needed."""
    global _config_loaded
    if not _config_loaded:
        _load_config()
        _config_loaded = True
    return _iicy_config

# Default naming function (camelCase)
def default_naming_function(name: str) -> str:
    """Convert snake_case to camelCase (default naming strategy)."""
    parts = name.split('_')
    return parts[0] + ''.join(word.capitalize() for word in parts[1:])


# Global configuration model
_iicy_config = IICYConfigModel()

# Configuration function for users to import and use
def configure(
    lambda_timeout: Optional[int] = None,
    lambda_memory: Optional[int] = None,
    lambda_runtime: Optional[str] = None,
    template_format_version: Optional[str] = None,
    default_stack_name: Optional[str] = None
):
    """
    Configure IICY framework settings.
    
    Args:
        lambda_timeout: Default timeout for Lambda functions (seconds)
        lambda_memory: Default memory for Lambda functions (MB)
        lambda_runtime: Default runtime for Lambda functions
        template_format_version: CloudFormation template format version
        default_stack_name: Default CloudFormation stack name
    """
    global _iicy_config
    
    # Update the model with provided values
    update_data = {}
    lambda_update = {}
    
    if lambda_timeout is not None:
        lambda_update['timeout'] = lambda_timeout
    if lambda_memory is not None:
        lambda_update['memory'] = lambda_memory
    if lambda_runtime is not None:
        lambda_update['runtime'] = lambda_runtime
    
    if lambda_update:
        update_data['lambda_'] = _iicy_config.lambda_.model_copy(update=lambda_update)
    
    if template_format_version is not None:
        update_data['template_format_version'] = template_format_version
    if default_stack_name is not None:
        update_data['default_stack_name'] = default_stack_name
    
    if update_data:
        _iicy_config = _iicy_config.model_copy(update=update_data)


def naming_strategy(func: Callable) -> Callable:
    """
    Decorator to set a custom naming strategy function.
    
    Usage:
        @naming_strategy
        def my_naming_function(function_name: str) -> str:
            return function_name.upper()
    """
    global _iicy_config
    lambda_update = _iicy_config.lambda_.model_copy(update={'custom_naming_function': func})
    _iicy_config = _iicy_config.model_copy(update={'lambda_': lambda_update})
    return func
