use std::time::Duration;

use async_trait::async_trait;
use serde::{Serialize, de::DeserializeOwned};

use crate::cache::{CacheKey, CacheResult};

/// Async cache store abstraction.
#[async_trait]
pub trait CacheStore: Send + Sync {
    /// Reads a raw value by key.
    async fn get_raw(&self, key: &CacheKey) -> CacheResult<Option<Vec<u8>>>;

    /// Writes a raw value with optional TTL.
    async fn set_raw(
        &self,
        key: &CacheKey,
        value: Vec<u8>,
        ttl: Option<Duration>,
    ) -> CacheResult<()>;

    /// Deletes a value by key.
    async fn delete(&self, key: &CacheKey) -> CacheResult<()>;

    /// Deletes multiple values by key.
    ///
    /// Backends can override this to batch keys by connection or shard. The
    /// default implementation preserves existing single-key semantics.
    async fn delete_many(&self, keys: &[CacheKey]) -> CacheResult<()> {
        for key in keys {
            self.delete(key).await?;
        }
        Ok(())
    }

    /// Reads a JSON value by key.
    async fn get_json<T>(&self, key: &CacheKey) -> CacheResult<Option<T>>
    where
        T: DeserializeOwned + Send,
    {
        match self.get_raw(key).await? {
            Some(bytes) => Ok(Some(serde_json::from_slice(&bytes)?)),
            None => Ok(None),
        }
    }

    /// Writes a JSON value with optional TTL.
    async fn set_json<T>(&self, key: &CacheKey, value: &T, ttl: Option<Duration>) -> CacheResult<()>
    where
        T: Serialize + Sync,
    {
        self.set_raw(key, serde_json::to_vec(value)?, ttl).await
    }
}
