Documentation
use std::{
    collections::HashMap,
    sync::{Arc, Mutex},
};

#[derive(Debug, Clone)]
pub struct KVEngine {
    kv: Arc<Mutex<HashMap<String, String>>>,
}

#[derive(Debug, Clone, thiserror::Error)]
pub enum KVError {
    #[error("Key not found")]
    KeyNotFound,
    #[error("lock failed")]
    LockFailed,
}

pub type KVResult<T> = std::result::Result<T, KVError>;

impl Default for KVEngine {
    fn default() -> Self {
        KVEngine {
            kv: Arc::new(Mutex::new(HashMap::new())),
        }
    }
}

impl KVEngine {
    pub fn new() -> Self {
        Default::default()
    }

    pub fn set_key_value(&self, key: String, value: String) -> KVResult<()> {
        let Ok(mut kv) = self.kv.lock() else {
            if self.kv.is_poisoned() {
                self.kv.clear_poison();
            }
            return Err(KVError::LockFailed);
        };
        kv.insert(key, value);
        Ok(())
    }

    pub fn get_key_value(&self, key: &str) -> KVResult<String> {
        let Ok(kv) = self.kv.lock() else {
            if self.kv.is_poisoned() {
                self.kv.clear_poison();
            }
            return Err(KVError::LockFailed);
        };
        match kv.get(key) {
            Some(value) => Ok(value.to_owned()),
            None => Err(KVError::KeyNotFound),
        }
    }

    pub fn delete_key_value(&self, key: &str) -> KVResult<()> {
        let Ok(mut kv) = self.kv.lock() else {
            if self.kv.is_poisoned() {
                self.kv.clear_poison();
            }
            return Err(KVError::LockFailed);
        };
        if kv.remove(key).is_none() {
            return Err(KVError::KeyNotFound);
        }
        Ok(())
    }

    pub fn clear_all(&self) -> KVResult<()> {
        let Ok(mut kv) = self.kv.lock() else {
            if self.kv.is_poisoned() {
                self.kv.clear_poison();
            }
            return Err(KVError::LockFailed);
        };
        kv.clear();
        Ok(())
    }
}