"""
Retry mechanism for health checks with configurable attempts and delays.
"""

import time
import logging
from typing import Callable, Any, Optional
from functools import wraps

logger = logging.getLogger(__name__)


class RetryHandler:
    """Handles retry logic for health checks with configurable policies."""
    
    def __init__(self, max_retries: int = 3, base_delay: float = 1.0, backoff_factor: float = 2.0):
        """
        Initialize retry handler.
        
        Args:
            max_retries: Maximum number of retry attempts
            base_delay: Initial delay between retries in seconds
            backoff_factor: Multiplier for exponential backoff
        """
        self.max_retries = max_retries
        self.base_delay = base_delay
        self.backoff_factor = backoff_factor
    
    def execute_with_retry(self, func: Callable, *args, **kwargs) -> Any:
        """
        Execute a function with retry logic.
        
        Args:
            func: Function to execute
            *args: Function arguments
            **kwargs: Function keyword arguments
            
        Returns:
            Result of the function call
            
        Raises:
            Exception: Reraises the last exception if all retries fail
        """
        last_exception = None
        
        for attempt in range(self.max_retries + 1):
            try:
                return func(*args, **kwargs)
            except Exception as e:
                last_exception = e
                
                if attempt < self.max_retries:
                    delay = self.base_delay * (self.backoff_factor ** attempt)
                    logger.warning(
                        f"Attempt {attempt + 1} failed. Retrying in {delay:.2f}s. Error: {str(e)}"
                    )
                    time.sleep(delay)
                else:
                    logger.error(
                        f"All {self.max_retries + 1} attempts failed. Final error: {str(e)}"
                    )
        
        raise last_exception


def retry_on_failure(max_retries: int = 3, base_delay: float = 1.0, 
                    backoff_factor: float = 2.0, exceptions: tuple = (Exception,)):
    """
    Decorator for automatic retry on function failure.
    
    Args:
        max_retries: Maximum number of retry attempts
        base_delay: Initial delay between retries
        backoff_factor: Multiplier for exponential backoff
        exceptions: Tuple of exceptions to catch and retry on
        
    Returns:
        Decorated function with retry logic
    """
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            retry_handler = RetryHandler(max_retries, base_delay, backoff_factor)
            return retry_handler.execute_with_retry(func, *args, **kwargs)
        return wrapper
    return decorator