from __future__ import annotations

import time
from typing import Optional

import anyio

from .._exceptions import GenerationFailedError, GenerationTimeoutError
from .._models import FinalRequestOptions
from .._resource import AsyncAPIResource, SyncAPIResource
from .._types import NOT_GIVEN, NotGiven
from ..types.generation import Generation


class Generations(SyncAPIResource):
    def get(self, request_id: str) -> Generation:
        return self._get(f"/generations/{request_id}", cast_to=Generation)

    def wait(
        self,
        request_id: str,
        *,
        poll_interval: float = 2.0,
        timeout: float = 600.0,
    ) -> Generation:
        deadline = time.monotonic() + timeout
        interval = poll_interval
        while True:
            gen = self.get(request_id)
            if gen.status == "succeeded":
                return gen
            if gen.status == "failed":
                raise GenerationFailedError(generation=gen)
            if time.monotonic() > deadline:
                raise GenerationTimeoutError(request_id=request_id, timeout=timeout)
            self._sleep(min(interval, max(deadline - time.monotonic(), 0.1)))
            interval = min(interval * 1.5, 10.0)


class AsyncGenerations(AsyncAPIResource):
    async def get(self, request_id: str) -> Generation:
        return await self._get(f"/generations/{request_id}", cast_to=Generation)

    async def wait(
        self,
        request_id: str,
        *,
        poll_interval: float = 2.0,
        timeout: float = 600.0,
    ) -> Generation:
        deadline = time.monotonic() + timeout
        interval = poll_interval
        while True:
            gen = await self.get(request_id)
            if gen.status == "succeeded":
                return gen
            if gen.status == "failed":
                raise GenerationFailedError(generation=gen)
            if time.monotonic() > deadline:
                raise GenerationTimeoutError(request_id=request_id, timeout=timeout)
            await self._sleep(min(interval, max(deadline - time.monotonic(), 0.1)))
            interval = min(interval * 1.5, 10.0)
