"""Common dependency injection utilities."""

from functools import lru_cache
from typing import AsyncGenerator, Optional

from common.core.config import CommonConfig
from common.database import Db, DBConfig
from common.logging import get_logger

logger = get_logger(__name__)


@lru_cache()
def get_common_config() -> CommonConfig:
    """Get cached common configuration."""
    return CommonConfig()


async def get_database() -> AsyncGenerator[Db, None]:
    """
    Get database connection with proper cleanup.

    Yields:
        Db: Database connection instance
    """
    config = DBConfig()
    db = Db(config)
    try:
        yield db
    finally:
        # Add any cleanup logic here if needed
        pass


class CircuitBreaker:
    """Simple circuit breaker for external service calls."""

    def __init__(
        self,
        failure_threshold: int = 5,
        recovery_timeout: int = 60,
        expected_exception: type[Exception] = Exception,
    ):
        self.failure_threshold = failure_threshold
        self.recovery_timeout = recovery_timeout
        self.expected_exception = expected_exception
        self.failure_count = 0
        self.last_failure_time: Optional[float] = None
        self.is_open = False

    async def call(self, func, *args, **kwargs):
        """Execute function with circuit breaker protection."""
        if self.is_open:
            if self.last_failure_time is None:
                self.is_open = False
            else:
                import time

                if time.time() - self.last_failure_time >= self.recovery_timeout:
                    self.is_open = False
                    self.failure_count = 0
                else:
                    raise Exception("Circuit breaker is open")

        try:
            result = await func(*args, **kwargs)
            self.failure_count = 0
            return result
        except self.expected_exception as e:
            self.failure_count += 1
            if self.failure_count >= self.failure_threshold:
                self.is_open = True
                import time

                self.last_failure_time = time.time()
                logger.error(
                    f"Circuit breaker opened after {self.failure_count} failures"
                )
            raise e
