"""Base classes and configuration for fallback mechanisms."""

import asyncio
import json
import logging
from dataclasses import dataclass, field
from datetime import datetime, timezone
from typing import Any, Callable, Dict, List, Optional, TypeVar, Union
from contextlib import asynccontextmanager

from ...errors import TraxError, ErrorCode, ErrorCategory, ErrorSeverity
from ...logging import get_logger

logger = get_logger(__name__)

T = TypeVar('T')


@dataclass
class FallbackConfig:
    """Configuration for fallback mechanisms."""
    enabled: bool = True
    max_fallbacks: int = 3
    timeout: float = 30.0
    cache_ttl: int = 3600  # 1 hour
    retry_on_fallback_failure: bool = True
    log_fallback_attempts: bool = True


class FallbackProvider:
    """Base class for fallback providers."""
    
    def __init__(self, name: str, priority: int = 0):
        self.name = name
        self.priority = priority
        self.logger = get_logger(f"{__name__}.{name}")
    
    async def is_available(self) -> bool:
        """Check if this provider is available."""
        raise NotImplementedError
    
    async def execute(self, *args, **kwargs) -> Any:
        """Execute the fallback operation."""
        raise NotImplementedError
    
    async def get_health_status(self) -> Dict[str, Any]:
        """Get health status of this provider."""
        return {
            "name": self.name,
            "available": await self.is_available(),
            "priority": self.priority
        }


# Context manager for fallback operations
@asynccontextmanager
async def fallback_context(fallback_manager):
    """Context manager for fallback operations."""
    try:
        yield fallback_manager
    except Exception as e:
        logger.error(f"Fallback context error: {e}")
        raise


# Decorator for automatic fallback handling
def with_fallbacks(
    fallback_manager,
    timeout: Optional[float] = None
):
    """Decorator to add fallback support to functions."""
    def decorator(func: Callable) -> Callable:
        async def wrapper(*args, **kwargs):
            config = fallback_manager.config
            if timeout is not None:
                config.timeout = timeout
            
            return await fallback_manager.execute_with_fallbacks(func, *args, **kwargs)
        
        return wrapper
    return decorator
