from types import TracebackType
from typing import Optional, Type, Union

from . import _momento_endpoint_resolver
from ._utilities._data_validation import _validate_request_timeout
from .cache_operation_types import (
    CacheDeleteResponse,
    CacheGetResponse,
    CacheSetResponse,
    CreateCacheResponse,
    DeleteCacheResponse,
    ListCachesResponse,
)
from .internal.synchronous._scs_control_client import _ScsControlClient
from .internal.synchronous._scs_data_client import _ScsDataClient


class SimpleCacheClient:
    def __init__(
        self,
        auth_token: str,
        default_ttl_seconds: int,
        request_timeout_ms: Optional[int] = None,
    ):
        """Creates an async SimpleCacheClient

        Args:
            auth_token (str): Momento Token to authenticate the requests with Simple Cache Service
            default_ttl_seconds (int): A default Time To Live in seconds for cache objects created by this client. It is
                possible to override this setting when calling the set method.
            request_timeout_ms (Optional[int], optional): An optional timeout in milliseconds to allow for Get and Set
                operations to complete. The request will be terminated if it takes longer than this value and will
                result in TimeoutError. Defaults to None, in which case a 5 second timeout is used.
        Raises:
            IllegalArgumentError: If method arguments fail validations.
        """
        _validate_request_timeout(request_timeout_ms)

        endpoints = _momento_endpoint_resolver.resolve(auth_token)
        self._control_client = _ScsControlClient(auth_token, endpoints.control_endpoint)
        self._data_client = _ScsDataClient(
            auth_token,
            endpoints.cache_endpoint,
            default_ttl_seconds,
            request_timeout_ms,
        )

    def __enter__(self) -> "SimpleCacheClient":
        return self

    def __exit__(
        self,
        exc_type: Optional[Type[BaseException]],
        exc_value: Optional[BaseException],
        traceback: Optional[TracebackType],
    ) -> None:
        self._control_client.close()
        self._data_client.close()

    def create_cache(self, cache_name: str) -> CreateCacheResponse:
        """Creates a new cache in your Momento account.

        Args:
            cache_name: String used to create cache.

        Returns:
            CreateCacheResponse

        Raises:
            InvalidArgumentError: If provided cache_name is None.
            BadRequestError: If the cache name provided doesn't follow the naming conventions
            AlreadyExistsError: If cache with the given name already exists.
            AuthenticationError: If the provided Momento Auth Token is invalid.
            ClientSdkError: For any SDK checks that fail.
        """
        return self._control_client.create_cache(cache_name)

    def delete_cache(self, cache_name: str) -> DeleteCacheResponse:
        """Deletes a cache and all the items within it.

        Args:
            cache_name: String cache name to delete.

        Returns:
            DeleteCacheResponse

        Raises:
            InvalidArgumentError: If provided cache_name is None.
            BadRequestError: If the cache name provided doesn't follow the naming conventions
            NotFoundError: If an attempt is made to delete a MomentoCache that doesn't exist.
            AuthenticationError: If the provided Momento Auth Token is invalid.
            ClientSdkError: For any SDK checks that fail.
        """
        return self._control_client.delete_cache(cache_name)

    def list_caches(self, next_token: Optional[str] = None) -> ListCachesResponse:
        """Lists all caches.

        Args:
            next_token: Token to continue paginating through the list. It's used to handle large paginated lists.

        Returns:
            ListCachesResponse

        Raises:
            AuthenticationError: If the provided Momento Auth Token is invalid.
        """
        return self._control_client.list_caches(next_token)

    def set(
        self,
        cache_name: str,
        key: Union[str, bytes],
        value: Union[str, bytes],
        ttl_seconds: Optional[int] = None,
    ) -> CacheSetResponse:
        """Stores an item in cache

        Args:
            cache_name: Name of the cache to store the item in.
            key (string or bytes): The key to be used to store item.
            value (string or bytes): The value to be stored.
            ttl_seconds (Optional): Time to live in cache in seconds. If not provided, then default TTL for the cache
                client instance is used.

        Returns:
            CacheSetResponse

        Raises:
            InvalidArgumentError: If validation fails for the provided method arguments.
            BadRequestError: If the provided inputs are rejected by server because they are invalid
            NotFoundError: If the cache with the given name doesn't exist.
            AuthenticationError: If the provided Momento Auth Token is invalid.
            InternalServerError: If server encountered an unknown error while trying to store the item.
        """
        return self._data_client.set(cache_name, key, value, ttl_seconds)

    def get(self, cache_name: str, key: Union[str, bytes]) -> CacheGetResponse:
        """Retrieve an item from the cache

        Args:
            cache_name: Name of the cache to get the item from
            key (string or bytes): The key to be used to retrieve the item.

        Returns:
            CacheGetResponse

        Raises:
            InvalidArgumentError: If validation fails for the provided method arguments.
            BadRequestError: If the provided inputs are rejected by server because they are invalid
            NotFoundError: If the cache with the given name doesn't exist.
            AuthenticationError: If the provided Momento Auth Token is invalid.
            InternalServerError: If server encountered an unknown error while trying to retrieve the item.
        """
        return self._data_client.get(cache_name, key)

    def delete(self, cache_name: str, key: Union[str, bytes]) -> CacheDeleteResponse:
        """Delete an item from the cache.

        Performs a no-op if the item is not in the cache.

        Args:
            cache_name: Name of the cache to delete the item from.
            key (string or bytes): The key to delete.

        Returns:
            CacheDeleteResponse

        Raises:
            InvalidArgumentError: If validation fails for provided method arguments.
            BadRequestError: If the provided inputs are rejected by server because they are invalid
            NotFoundError: If the cache with the given name doesn't exist.
            AuthenticationError: If the provided Momento Auth Token is invalid.
            InternalServerError: If server encountered an unknown error while trying to delete the item.
        """
        return self._data_client.delete(cache_name, key)
