from typing import TYPE_CHECKING, Any

from ._cache import AsyncResolver, SyncResolver
from ._internal._schemas.images import ArtworkDetails
from ._internal._schemas.models import GenerationParameters

if TYPE_CHECKING:
    from ._async_client import AsyncClient
    from ._sync_client import SyncClient
else:
    AsyncClient = Any
    SyncClient = Any


class AsyncClientCache:
    """TTL-cached resolvers for expensive async API lookups.

    Attributes:
        model_ver_no: Resolves a model number to its latest version number.
        gen_params: Resolves a ``(model_no, model_ver_no)`` pair to generation parameters.
        task_id_detail: Resolves a task ID to its ``ArtworkDetails``.
    """

    def __init__(self, client: AsyncClient) -> None:
        self._client = client
        self.model_ver_no = AsyncResolver(
            self._fetch_model_ver_no, ttl_seconds=client.cfg.cache_ttl_seconds
        )
        self.gen_params = AsyncResolver(
            self._fetch_gen_params, ttl_seconds=client.cfg.cache_ttl_seconds
        )
        self.task_id_detail = AsyncResolver(
            self._resolve_task_id_detail, ttl_seconds=client.cfg.cache_ttl_seconds
        )

    async def _fetch_model_ver_no(self, model_no: str) -> str:
        envelope = await self._client.models.detail(model_no)
        return envelope.value.model_ver_no

    async def _fetch_gen_params(self, key: tuple[str, str]) -> GenerationParameters:
        model_no, model_ver_no = key
        envelope = await self._client.models.generation_parameters(
            model_no, model_ver_no
        )
        return envelope.value

    async def _resolve_task_id_detail(self, task_id: str) -> ArtworkDetails:
        detail = await self._client.images.detail(task_id)
        return detail.value


class SyncClientCache:
    """TTL-cached resolvers for expensive sync API lookups.

    Attributes:
        model_ver_no: Resolves a model number to its latest version number.
        gen_params: Resolves a ``(model_no, model_ver_no)`` pair to generation parameters.
        task_id_detail: Resolves a task ID to its ``ArtworkDetails``.
    """

    def __init__(self, client: SyncClient) -> None:
        self._client = client
        self.model_ver_no = SyncResolver(
            self._fetch_model_ver_no, ttl_seconds=client.cfg.cache_ttl_seconds
        )
        self.gen_params = SyncResolver(
            self._fetch_gen_params, ttl_seconds=client.cfg.cache_ttl_seconds
        )
        self.task_id_detail = SyncResolver(
            self._resolve_task_id_detail, ttl_seconds=client.cfg.cache_ttl_seconds
        )

    def _fetch_model_ver_no(self, model_no: str) -> str:
        envelope = self._client.models.detail(model_no)
        return envelope.value.model_ver_no

    def _fetch_gen_params(self, key: tuple[str, str]) -> GenerationParameters:
        model_no, model_ver_no = key
        envelope = self._client.models.generation_parameters(model_no, model_ver_no)
        return envelope.value

    def _resolve_task_id_detail(self, task_id: str) -> ArtworkDetails:
        detail = self._client.images.detail(task_id)
        return detail.value
