"""Base engine class for all tool category engines."""

from __future__ import annotations

from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Any, Dict, Optional

from ..logging import get_logger
from ..meta_client import MetaClient


@dataclass
class EngineConfig:
    """Configuration for engine instances.
    
    Attributes:
        cache_enabled: Whether to use caching for this engine
        rate_limit_enabled: Whether to apply rate limiting
        timeout: Operation timeout in seconds
        max_retries: Maximum number of retries for failed operations
        custom_settings: Engine-specific custom settings
    """
    cache_enabled: bool = False
    rate_limit_enabled: bool = True
    timeout: float = 30.0
    max_retries: int = 3
    custom_settings: Dict[str, Any] = None
    
    def __post_init__(self) -> None:
        """Initialize custom_settings if None."""
        if self.custom_settings is None:
            self.custom_settings = {}


class BaseEngine(ABC):
    """Base class for all tool category engines.
    
    Provides consistent interface for initialization, shutdown, and lifecycle management.
    All engine implementations should inherit from this class.
    
    Attributes:
        client: Meta API client instance
        config: Engine configuration
        logger: Logger instance for this engine
    """
    
    def __init__(self, client: MetaClient, config: Optional[EngineConfig] = None):
        """Initialize the engine.
        
        Args:
            client: Meta API client instance
            config: Engine configuration (defaults to EngineConfig())
        """
        self.client = client
        self.config = config or EngineConfig()
        self.logger = get_logger(self.__class__.__name__)
        self._initialized = False
        self._shutdown = False
    
    @abstractmethod
    async def initialize(self) -> None:
        """Initialize engine resources.
        
        Called once during engine startup. Override to perform async initialization
        such as warming caches, establishing connections, or loading data.
        
        Raises:
            RuntimeError: If initialization fails
        """
        pass
    
    @abstractmethod
    async def shutdown(self) -> None:
        """Clean up engine resources.
        
        Called during server shutdown. Override to perform cleanup such as
        closing connections, flushing caches, or releasing resources.
        """
        pass
    
    async def _ensure_initialized(self) -> None:
        """Ensure the engine is initialized before use.
        
        Raises:
            RuntimeError: If engine is not initialized or has been shut down
        """
        if self._shutdown:
            raise RuntimeError(f"{self.__class__.__name__} has been shut down")
        
        if not self._initialized:
            await self.initialize()
            self._initialized = True
    
    async def _mark_shutdown(self) -> None:
        """Mark the engine as shut down."""
        self._shutdown = True
        self._initialized = False
    
    def is_initialized(self) -> bool:
        """Check if the engine is initialized.
        
        Returns:
            True if initialized, False otherwise
        """
        return self._initialized and not self._shutdown
    
    def get_config_value(self, key: str, default: Any = None) -> Any:
        """Get a custom configuration value.
        
        Args:
            key: Configuration key
            default: Default value if key not found
            
        Returns:
            Configuration value or default
        """
        return self.config.custom_settings.get(key, default)
    
    def log_operation(self, operation: str, **kwargs) -> None:
        """Log an engine operation with context.
        
        Args:
            operation: Operation name
            **kwargs: Additional context to log
        """
        self.logger.info(
            operation,
            engine=self.__class__.__name__,
            **kwargs
        )
    
    def log_error(self, operation: str, error: Exception, **kwargs) -> None:
        """Log an engine error with context.
        
        Args:
            operation: Operation name
            error: Exception that occurred
            **kwargs: Additional context to log
        """
        self.logger.error(
            f"{operation}_failed",
            engine=self.__class__.__name__,
            error=str(error),
            error_type=type(error).__name__,
            **kwargs
        )


class NoOpEngine(BaseEngine):
    """No-operation engine for testing.
    
    A simple engine implementation that does nothing. Useful for testing
    the engine interface without actual functionality.
    """
    
    async def initialize(self) -> None:
        """Initialize (no-op)."""
        self.log_operation("initialize")
    
    async def shutdown(self) -> None:
        """Shutdown (no-op)."""
        self.log_operation("shutdown")

