from http.client import HTTPException
import os
import sys
import logging
import json

# Add the project root to the path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')))

from pydantic import BaseModel
from typing import Dict, Any, Optional, List

from wflite.registry.db_registry import StateMachineRegistry
from wflite.runtime.statemachine_runtime import StateMachineRuntime
from wflite.config.config_loader import ConfigLoader
from wflite.persistence.provider_factory import PersistenceProviderFactory

# Import KeyVault helper (to be created)
try:
    from wflite.config.azure_keyvault import get_keyvault_secrets
except ImportError:
    # Define a placeholder function if the module is not available
    def get_keyvault_secrets():
        return {}

# Configure logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

# Define request models
class EventRequest(BaseModel):
    customer_id: str
    event_name: str
    event_details: Optional[Dict[str, Any]] = None

def initialize_runtime(config_json: Optional[Dict[str, Any]] = None):
    """
    Initialize runtime components with the provided configuration or from environment.
    
    Args:
        config_json: Optional configuration dictionary to override the default config
        
    Returns:
        Tuple of (StateMachineRegistry, StateMachineRuntime, config)
    """
    # Create config loader - will load from environment variables
    config_loader = ConfigLoader()
    
    # Try to load secrets from Azure Key Vault
    try:
        keyvault_secrets = get_keyvault_secrets()
        if keyvault_secrets:
            logger.info("Successfully loaded secrets from Azure Key Vault")
            # No need to manually apply them as they're set as environment variables
            # and will be processed by the config_loader
    except Exception as e:
        logger.warning(f"Failed to load secrets from Azure Key Vault: {str(e)}")
    
    # Override config if provided (request config overrides KeyVault and env vars)
    if config_json:
        config_loader._config.update(config_json)
    
    config = config_loader._config
    
    # Create persistence provider
    persistence_provider = PersistenceProviderFactory.create_provider(config)
    
    # Log the selected provider
    provider_type = config.get('persistence', {}).get('provider', 'sqlite')
    logger.info(f"Using persistence provider: {provider_type}")
    
    # Create registry
    registry = StateMachineRegistry()
    
    # Create runtime with the configured persistence provider
    runtime = StateMachineRuntime(
        persistence_provider=persistence_provider,
        registry_provider=registry
    )
    
    logger.info(f"Serverless runtime initialized with {provider_type} persistence provider")
    
    return registry, runtime, config

def trigger_event(request: EventRequest, config_json: Optional[Dict[str, Any]] = None):
    """
    Trigger an event for a customer's workflow instance, suitable for serverless environments.
    
    Args:
        request: Either EventRequest object or dict/JSON with customer_id, event_name, and optional event_details
        config_json: Optional configuration to initialize the runtime
        
    Returns:
        Dict with event processing result
    """
    try:
        # Convert request to EventRequest if it's a dict
        if not isinstance(request, EventRequest):
            if hasattr(request, 'get_json'):
                # Handle Flask/Function request objects
                request_data = request.get_json()
            elif isinstance(request, dict):
                request_data = request
            elif isinstance(request, str):
                # Try parsing a JSON string
                request_data = json.loads(request)
            else:
                logger.error(f"Unsupported request type: {type(request)}")
                raise ValueError("Invalid request format")
                
            request = EventRequest(
                customer_id=request_data.get('customer_id'),
                event_name=request_data.get('event_name'),
                event_details=request_data.get('event_details')
            )
            
        logger.info(f"Processing event '{request.event_name}' for customer {request.customer_id}")
        
        # Initialize runtime components
        registry, runtime, _ = initialize_runtime(config_json)
        
        # Get customer's workflow instance
        template_name, instance_id = runtime.get_customer_instance(request.customer_id)
        
        if not template_name or not instance_id:
            logger.error(f"No workflow assigned to customer {request.customer_id}")
            return {
                "success": False,
                "error": f"No workflow assigned to customer {request.customer_id}"
            }
        
        # Get template data
        template_data = registry.load(template_name)
        if not template_data:
            logger.error(f"Template {template_name} not found")
            return {
                "success": False,
                "error": f"Template {template_name} not found"
            }
            
        # Process the event
        success, actions = runtime.trigger_event(
            instance_id=instance_id,
            event_name=request.event_name,
            template_data=template_data,
            event_details=request.event_details
        )
        
        if not success:
            logger.error(f"Event '{request.event_name}' could not be processed")
            return {
                "success": False,
                "error": f"Event '{request.event_name}' could not be processed"
            }
        
        # Get updated state info
        current_state = runtime.get_current_state(instance_id, template_data)
        context = runtime.get_context(instance_id)
        
        return {
            "success": True,
            "customer_id": request.customer_id,
            "instance_id": instance_id,
            "template_name": template_name,
            "current_state": current_state["id"],
            "state_name": current_state["name"],
            "context": context,
            "actions": actions
        }
        
    except Exception as e:
        logger.error(f"Error processing event: {str(e)}")
        return {
            "success": False,
            "error": str(e)
        }

# Example of Azure Function handler
def azure_function_handler(req):
    """
    Handler for Azure Functions integration.
    
    Example:
        import azure.functions as func
        
        def main(req: func.HttpRequest) -> func.HttpResponse:
            import json
            from wflite.runtime.serverless import azure_function_handler
            
            result = azure_function_handler(req)
            return func.HttpResponse(
                json.dumps(result),
                mimetype="application/json",
                status_code=200 if result.get('success') else 400
            )
    """
    try:
        # Get request body
        request_data = req.get_json() if hasattr(req, 'get_json') else req
        
        # Get configuration from request if available
        # This is now optional since we can use KeyVault and env vars instead
        config = request_data.get('config') if isinstance(request_data, dict) else None
        
        # Remove config from request data if present
        if isinstance(request_data, dict) and 'config' in request_data:
            request_data = {k: v for k, v in request_data.items() if k != 'config'}
        
        # Process the event
        return trigger_event(request_data, config)
        
    except Exception as e:
        logger.error(f"Azure function error: {str(e)}")
        return {
            "success": False,
            "error": str(e)
        }
