"""
Azure Blob Cache implementation

Has 4 methods:
    - set_cache
    - get_cache
    - async_set_cache
    - async_get_cache
"""

import asyncio
import json
from contextlib import suppress

from litellm._logging import print_verbose, verbose_logger

from .base_cache import BaseCache


class AzureBlobCache(BaseCache):
    def __init__(self, account_url, container) -> None:
        from azure.storage.blob import BlobServiceClient
        from azure.core.exceptions import ResourceExistsError
        from azure.identity import DefaultAzureCredential
        from azure.identity.aio import (
            DefaultAzureCredential as AsyncDefaultAzureCredential,
        )
        from azure.storage.blob.aio import BlobServiceClient as AsyncBlobServiceClient

        self.container_client = BlobServiceClient(
            account_url=account_url,
            credential=DefaultAzureCredential(),
        ).get_container_client(container)
        self.async_container_client = AsyncBlobServiceClient(
            account_url=account_url,
            credential=AsyncDefaultAzureCredential(),
        ).get_container_client(container)

        with suppress(ResourceExistsError):
            self.container_client.create_container()

    def set_cache(self, key, value, **kwargs) -> None:
        print_verbose(f"LiteLLM SET Cache - Azure Blob. Key={key}. Value={value}")
        serialized_value = json.dumps(value)
        try:
            self.container_client.upload_blob(key, serialized_value)
        except Exception as e:
            # NON blocking - notify users Azure Blob is throwing an exception
            print_verbose(f"LiteLLM set_cache() - Got exception from Azure Blob: {e}")

    async def async_set_cache(self, key, value, **kwargs) -> None:
        print_verbose(f"LiteLLM SET Cache - Azure Blob. Key={key}. Value={value}")
        serialized_value = json.dumps(value)
        try:
            await self.async_container_client.upload_blob(
                key, serialized_value, overwrite=True
            )
        except Exception as e:
            # NON blocking - notify users Azure Blob is throwing an exception
            print_verbose(f"LiteLLM set_cache() - Got exception from Azure Blob: {e}")

    def get_cache(self, key, **kwargs):
        from azure.core.exceptions import ResourceNotFoundError

        try:
            print_verbose(f"Get Azure Blob Cache: key: {key}")
            as_bytes = self.container_client.download_blob(key).readall()
            as_str = as_bytes.decode("utf-8")
            cached_response = json.loads(as_str)

            verbose_logger.debug(
                f"Got Azure Blob Cache: key: {key}, cached_response {cached_response}. Type Response {type(cached_response)}"
            )

            return cached_response
        except ResourceNotFoundError:
            return None

    async def async_get_cache(self, key, **kwargs):
        from azure.core.exceptions import ResourceNotFoundError

        try:
            print_verbose(f"Get Azure Blob Cache: key: {key}")
            blob = await self.async_container_client.download_blob(key)
            as_bytes = await blob.readall()
            as_str = as_bytes.decode("utf-8")
            cached_response = json.loads(as_str)
            verbose_logger.debug(
                f"Got Azure Blob Cache: key: {key}, cached_response {cached_response}. Type Response {type(cached_response)}"
            )
            return cached_response
        except ResourceNotFoundError:
            return None

    def flush_cache(self) -> None:
        for blob in self.container_client.walk_blobs():
            self.container_client.delete_blob(blob.name)

    async def disconnect(self) -> None:
        self.container_client.close()
        await self.async_container_client.close()

    async def async_set_cache_pipeline(self, cache_list, **kwargs) -> None:
        tasks = []
        for val in cache_list:
            tasks.append(self.async_set_cache(val[0], val[1], **kwargs))
        await asyncio.gather(*tasks)
