import asyncio
from typing import Awaitable, Callable, TypeVar

from app.core.constants import MAX_RETRIES

T = TypeVar("T")


class RetryExecutor:
    async def run(self, operation: Callable[[], Awaitable[T]]) -> T:
        last_error: Exception | None = None
        for attempt in range(1, MAX_RETRIES + 1):
            try:
                return await operation()
            except (TimeoutError, ConnectionError, OSError) as exc:
                last_error = exc
                if attempt == MAX_RETRIES:
                    break
                await asyncio.sleep(0.1 * attempt)
        assert last_error is not None
        raise last_error
