use crate::cache::get_hash;
use crate::common::{deserialize_from_json, get_items, serialize_to_json};
use cal_core::Proxy;
use redis::aio::MultiplexedConnection;
use redis::{AsyncCommands, RedisError, Value};

const PROXIES_KEY: &str = "cal:proxies";

/// Retrieves all proxies stored in Redis.
///
/// # Arguments
/// * `con` - Redis connection
///
/// # Returns
/// * `Result<Vec<Proxy>, RedisError>` - List of proxies or a Redis error
pub async fn get_proxies(con: MultiplexedConnection) -> Result<Vec<Proxy>, RedisError> {
    get_items(con, PROXIES_KEY).await
}

/// Retrieves a proxy by its identifier (could be an ID, IP, etc.).
///
/// # Arguments
/// * `con` - Redis connection
/// * `key` - Proxy identifier to look up
///
/// # Returns
/// * `Result<Option<Proxy>, RedisError>` - Proxy if found, None if not found, or a Redis error
pub async fn get_proxy_by_id(
    con: MultiplexedConnection,
    key: &str,
) -> Result<Option<Proxy>, RedisError> {
    match get_hash(con.clone(), PROXIES_KEY, key).await? {
        Some(proxy) => deserialize_from_json(&proxy),
        None => Ok(None),
    }
}

/// Inserts a proxy into Redis.
///
/// # Arguments
/// * `con` - Redis connection
/// * `proxy` - Proxy object to insert
///
/// # Returns
/// * `Result<(), RedisError>` - Success or a Redis error
pub async fn insert_proxy(mut con: MultiplexedConnection, proxy: Proxy) -> Result<(), RedisError> {
    let value = serialize_to_json(&proxy)?;
    let _: Value = con.hset(PROXIES_KEY, &proxy.id, value.clone()).await?;
    Ok(())
}

/// Inserts multiple proxies into Redis.
///
/// # Arguments
/// * `con` - Redis connection
/// * `proxies` - List of proxies to insert
///
/// # Returns
/// * `Result<(), RedisError>` - Success or a Redis error
pub async fn insert_proxies(
    con: MultiplexedConnection,
    proxies: Vec<Proxy>,
) -> Result<(), RedisError> {
    for proxy in proxies {
        insert_proxy(con.clone(), proxy).await?;
    }
    Ok(())
}
