import os
from typing import Optional, List, Dict
import httpx
import modal
from loguru import logger
from .VideoUtils import VideoUtils
from ..models.media_model import MediaSource
from ..models.web_model import LiveProductCaches


class KVCache:
    kv: modal.Dict
    cf_kv_id: str = os.environ.get("CF_KV_NAMESPACE_ID")
    cf_account_id: str = os.environ.get("CF_ACCOUNT_ID")
    cf_kv_api_token: str = os.environ.get("CF_KV_API_TOKEN")

    def __init__(self, kv_name: str, environment: str):
        # self.cf_kv_id = cf_kv_id
        self.kv = modal.Dict.from_name(kv_name, environment_name=environment, create_if_missing=True)
        if self.cf_kv_id:
            logger.info(f"Using KV space : {self.cf_kv_id}")
        else:
            logger.warning(f"CF_KV_NAMESPACE_ID为空, 如果是本地使用modal deploy时触发此警告可忽略")

    def batch_update_cloudflare_kv(self, caches: Dict[str, str]):
        with httpx.Client() as client:
            try:
                response = client.put(
                    f"https://api.cloudflare.com/client/v4/accounts/{self.cf_account_id}/storage/kv/namespaces/{self.cf_kv_id}/bulk",
                    headers={"Authorization": f"Bearer {self.cf_kv_api_token}"},
                    json=[
                        {
                            "based64": False,
                            "key": key,
                            "value": value,
                        }
                        for (key, value) in caches.items()
                    ]
                )
                response.raise_for_status()
            except httpx.RequestError as e:
                logger.error(f"An error occurred while put kv to cloudflare")
                raise e
            except httpx.HTTPStatusError as e:
                logger.error(f"HTTP error occurred while get kv from cloudflare {str(e)}")
                raise e
            except Exception as e:
                logger.error(f"An unexpected error occurred: {str(e)}")
                raise e

    def batch_remove_cloudflare_kv(self, keys: List[str]):
        with httpx.Client() as client:
            try:
                response = client.post(
                    f"https://api.cloudflare.com/client/v4/accounts/{self.cf_account_id}/storage/kv/namespaces/{self.cf_kv_id}/bulk/delete",
                    headers={"Authorization": f"Bearer {self.cf_kv_api_token}"},
                    json=keys
                )
                response.raise_for_status()
            except httpx.RequestError as e:
                logger.error(f"An error occurred while put kv to cloudflare")
                raise e
            except httpx.HTTPStatusError as e:
                logger.error(f"HTTP error occurred while get kv from cloudflare {str(e)}")
                raise e
            except Exception as e:
                logger.error(f"An unexpected error occurred: {str(e)}")
                raise e


class MediaSourceKVCache(KVCache):
    def get_cache(self, urn: str) -> Optional[MediaSource]:
        cache_json = self.kv.get(urn)
        if not cache_json:
            return None
        media = MediaSource.model_validate_json(cache_json)
        if media.local_available:
            try:
                media.metadata = VideoUtils.ffprobe_media_metadata(media.local_mount_path)
                media.content_length = os.path.getsize(media.local_mount_path)
            except Exception as e:
                logger.exception(e)
        return media

    def set_cache(self, media: MediaSource):
        if media.local_available:
            try:
                media.metadata = VideoUtils.ffprobe_media_metadata(media.local_mount_path)
                media.content_length = os.path.getsize(media.local_mount_path)
            except Exception as e:
                logger.exception(e)
        cache_json = media.model_dump_json()
        self.kv.put(media.urn, cache_json)

    def clear(self):
        self.kv.clear()

    def pop(self, urn: str, raise_exception: bool = True) -> Optional[MediaSource]:
        try:
            cache_json = self.kv.pop(urn)
        except KeyError:
            if raise_exception:
                raise KeyError("URN错误，资源不存在")
            return None
        return MediaSource.model_validate_json(cache_json)


class LiveProductKVCache(KVCache):
    cf_kv_id: str = os.environ.get("CF_PRODUCT_KV_NAMESPACE_ID")

    def get_cache(self, room_id: str) -> Optional[LiveProductCaches]:
        cache_json = self.kv.get(room_id)
        if not cache_json:
            return None
        live_products = LiveProductCaches.model_validate_json(cache_json)
        return live_products

    def set_cache(self, live_products: LiveProductCaches):
        cache_json = live_products.model_dump_json()
        self.kv.put(live_products.room_id, cache_json)

    def clear(self):
        self.kv.clear()

    def pop(self, room_id: str, raise_exception: bool = True) -> Optional[LiveProductCaches]:
        try:
            cache_json = self.kv.pop(room_id)
        except KeyError:
            if raise_exception:
                raise KeyError("ROOM_ID错误，资源不存在")
            return None
        return LiveProductCaches.model_validate_json(cache_json)
