"""Circuit breaker pattern implementation"""
from datetime import datetime, timedelta
from functools import wraps
from typing import Callable
from app.core.logging import get_logger
from app.core.exceptions import CircuitBreakerOpen

logger = get_logger(__name__)


class CircuitBreaker:
    """Circuit breaker for external API calls"""
    
    def __init__(self, failure_threshold: int = 5, timeout: int = 60):
        self.failure_threshold = failure_threshold
        self.timeout = timeout
        self.failures = 0
        self.last_failure_time = None
        self.state = "closed"  # closed, open, half_open
    
    def call(self, func: Callable) -> Callable:
        """Decorator to wrap function with circuit breaker"""
        @wraps(func)
        async def wrapper(*args, **kwargs):
            # Check if circuit is open
            if self.state == "open":
                if self.last_failure_time and \
                   datetime.now() - self.last_failure_time > timedelta(seconds=self.timeout):
                    self.state = "half_open"
                    logger.info("Circuit breaker entering half-open state")
                else:
                    raise CircuitBreakerOpen("Circuit breaker is OPEN")
            
            try:
                result = await func(*args, **kwargs)
                
                # Success in half-open state closes circuit
                if self.state == "half_open":
                    self.state = "closed"
                    self.failures = 0
                    logger.info("Circuit breaker closed")
                
                return result
                
            except Exception as e:
                self.failures += 1
                self.last_failure_time = datetime.now()
                
                if self.failures >= self.failure_threshold:
                    self.state = "open"
                    logger.error(f"Circuit breaker opened after {self.failures} failures")
                
                raise e
        
        return wrapper
    
    def reset(self) -> None:
        """Manually reset circuit breaker"""
        self.state = "closed"
        self.failures = 0
        self.last_failure_time = None
        logger.info("Circuit breaker manually reset")
