//! Key-Value store abstraction

use std::sync::Arc;
use std::time::Duration;

use dashmap::DashMap;

use crate::error::{ClusterError, Result};

/// KV store interface
///
/// Provides access to distributed key-value storage with namespace isolation.
pub struct Kv {
    namespaces: DashMap<String, Arc<KvNamespace>>,
    default_namespace: Arc<KvNamespace>,
}

impl Kv {
    /// Create a new KV store
    pub(crate) fn new() -> Self {
        let default_namespace = Arc::new(KvNamespace::new("default".to_string()));
        Self {
            namespaces: DashMap::new(),
            default_namespace,
        }
    }

    /// Get or create a namespace
    pub fn namespace(&self, name: &str) -> Arc<KvNamespace> {
        if name == "default" {
            return self.default_namespace.clone();
        }

        self.namespaces
            .entry(name.to_string())
            .or_insert_with(|| Arc::new(KvNamespace::new(name.to_string())))
            .clone()
    }

    /// Get the default namespace
    pub fn default_namespace(&self) -> &Arc<KvNamespace> {
        &self.default_namespace
    }

    // Convenience methods on default namespace

    /// Get a value by key from the default namespace
    pub async fn get(&self, key: impl AsRef<[u8]>) -> Result<Option<Vec<u8>>> {
        self.default_namespace.get(key).await
    }

    /// Put a value in the default namespace
    pub async fn put(&self, key: impl AsRef<[u8]>, value: impl AsRef<[u8]>) -> Result<u64> {
        self.default_namespace.put(key, value).await
    }

    /// Delete a key from the default namespace
    pub async fn delete(&self, key: impl AsRef<[u8]>) -> Result<bool> {
        self.default_namespace.delete(key).await
    }

    /// Compare-and-swap in the default namespace
    pub async fn compare_and_swap(
        &self,
        key: impl AsRef<[u8]>,
        expected_version: u64,
        value: impl AsRef<[u8]>,
    ) -> Result<CasResult> {
        self.default_namespace
            .compare_and_swap(key, expected_version, value)
            .await
    }
}

/// KV namespace for data isolation
pub struct KvNamespace {
    name: String,
    // TODO: Add storage backend and raft reference
}

impl KvNamespace {
    pub(crate) fn new(name: String) -> Self {
        Self { name }
    }

    /// Get the namespace name
    pub fn name(&self) -> &str {
        &self.name
    }

    /// Get a value by key
    pub async fn get(&self, _key: impl AsRef<[u8]>) -> Result<Option<Vec<u8>>> {
        // TODO: Implement with storage backend
        Ok(None)
    }

    /// Get with revision
    pub async fn get_with_revision(
        &self,
        _key: impl AsRef<[u8]>,
    ) -> Result<Option<(Vec<u8>, u64)>> {
        // TODO: Implement with storage backend
        Ok(None)
    }

    /// Put a value (goes through Raft if available)
    pub async fn put(&self, _key: impl AsRef<[u8]>, _value: impl AsRef<[u8]>) -> Result<u64> {
        // TODO: Implement with Raft
        Ok(0)
    }

    /// Put with options
    pub async fn put_with_options(
        &self,
        _key: impl AsRef<[u8]>,
        _value: impl AsRef<[u8]>,
        _options: KvOptions,
    ) -> Result<KvPutResult> {
        // TODO: Implement with Raft
        Ok(KvPutResult {
            revision: 0,
            prev_value: None,
        })
    }

    /// Delete a key
    pub async fn delete(&self, _key: impl AsRef<[u8]>) -> Result<bool> {
        // TODO: Implement with Raft
        Ok(false)
    }

    /// Compare-and-swap
    pub async fn compare_and_swap(
        &self,
        _key: impl AsRef<[u8]>,
        expected_version: u64,
        _value: impl AsRef<[u8]>,
    ) -> Result<CasResult> {
        // TODO: Implement with storage backend
        Err(ClusterError::VersionMismatch {
            expected: expected_version,
            actual: 0,
        })
    }

    /// Scan keys with prefix
    pub async fn scan_prefix(
        &self,
        _prefix: impl AsRef<[u8]>,
        _limit: u32,
    ) -> Result<Vec<KvEntry>> {
        // TODO: Implement with storage backend
        Ok(Vec::new())
    }

    /// Scan keys in a range
    pub async fn scan_range(
        &self,
        _start: impl AsRef<[u8]>,
        _end: impl AsRef<[u8]>,
        _limit: u32,
    ) -> Result<Vec<KvEntry>> {
        // TODO: Implement with storage backend
        Ok(Vec::new())
    }

    /// Get with specified consistency level
    pub async fn get_with_consistency(
        &self,
        _key: impl AsRef<[u8]>,
        _consistency: ReadConsistency,
    ) -> Result<Option<Vec<u8>>> {
        // TODO: Implement with consistency options
        Ok(None)
    }
}

/// Options for KV operations
#[derive(Debug, Clone, Default)]
pub struct KvOptions {
    /// Lease ID for TTL-based expiration
    pub lease_id: Option<u64>,

    /// Return previous value
    pub prev_kv: bool,

    /// Time-to-live for the key
    pub ttl: Option<Duration>,
}

/// Result of a put operation
#[derive(Debug, Clone)]
pub struct KvPutResult {
    /// New revision after the put
    pub revision: u64,

    /// Previous value, if requested and existed
    pub prev_value: Option<Vec<u8>>,
}

/// A key-value entry with metadata
#[derive(Debug, Clone)]
pub struct KvEntry {
    /// The key
    pub key: Vec<u8>,

    /// The value
    pub value: Vec<u8>,

    /// Revision when the key was created
    pub create_revision: u64,

    /// Revision when the key was last modified
    pub mod_revision: u64,

    /// Version number (increments on each update)
    pub version: u64,

    /// Lease ID if the key is attached to a lease
    pub lease_id: Option<u64>,
}

/// Result of a compare-and-swap operation
#[derive(Debug, Clone)]
pub enum CasResult {
    /// CAS succeeded, contains new revision
    Success(u64),

    /// CAS failed due to version mismatch
    Conflict {
        /// Expected version
        expected: u64,
        /// Actual version found
        actual: u64,
    },

    /// Key did not exist
    NotFound,
}

/// Read consistency level
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum ReadConsistency {
    /// Read from local storage (may be stale)
    Local,

    /// Read from any node, but verify with leader's committed index
    Serializable,

    /// Read only from leader (linearizable, strongest guarantee)
    #[default]
    Linearizable,
}

/// Lightweight handle for KV operations
#[derive(Clone)]
pub struct KvHandle {
    kv: Arc<Kv>,
}

impl KvHandle {
    pub(crate) fn new(kv: Arc<Kv>) -> Self {
        Self { kv }
    }

    /// Get the underlying KV store
    pub fn inner(&self) -> &Arc<Kv> {
        &self.kv
    }

    /// Get a value by key
    pub async fn get(&self, key: impl AsRef<[u8]>) -> Result<Option<Vec<u8>>> {
        self.kv.get(key).await
    }

    /// Put a value
    pub async fn put(&self, key: impl AsRef<[u8]>, value: impl AsRef<[u8]>) -> Result<u64> {
        self.kv.put(key, value).await
    }

    /// Delete a key
    pub async fn delete(&self, key: impl AsRef<[u8]>) -> Result<bool> {
        self.kv.delete(key).await
    }

    /// Get a namespace
    pub fn namespace(&self, name: &str) -> Arc<KvNamespace> {
        self.kv.namespace(name)
    }
}
