//! Key-Value entry types with MVCC versioning

use serde::{Deserialize, Serialize};

/// Revision number for MVCC-style versioning
/// Each write operation increments the global revision counter
pub type Revision = u64;

/// A key-value entry with metadata
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Default)]
pub struct KvEntry {
    /// The key
    pub key: Vec<u8>,
    /// The value
    pub value: Vec<u8>,
    /// Revision when this key was created
    pub create_revision: Revision,
    /// Revision of the last modification
    pub mod_revision: Revision,
    /// Number of modifications since creation
    pub version: u64,
    /// Optional lease ID for TTL-based expiration
    pub lease_id: Option<i64>,
}

impl KvEntry {
    /// Create a new KV entry for initial insertion
    pub fn new(key: Vec<u8>, value: Vec<u8>, revision: Revision) -> Self {
        Self {
            key,
            value,
            create_revision: revision,
            mod_revision: revision,
            version: 1,
            lease_id: None,
        }
    }

    /// Create a new KV entry with lease
    pub fn with_lease(key: Vec<u8>, value: Vec<u8>, revision: Revision, lease_id: i64) -> Self {
        Self {
            key,
            value,
            create_revision: revision,
            mod_revision: revision,
            version: 1,
            lease_id: Some(lease_id),
        }
    }

    /// Update the entry with a new value and revision
    pub fn update(&self, value: Vec<u8>, revision: Revision) -> Self {
        Self {
            key: self.key.clone(),
            value,
            create_revision: self.create_revision,
            mod_revision: revision,
            version: self.version + 1,
            lease_id: self.lease_id,
        }
    }

    /// Get the key as a string (lossy conversion)
    pub fn key_str(&self) -> String {
        String::from_utf8_lossy(&self.key).to_string()
    }

    /// Get the value as a string (lossy conversion)
    pub fn value_str(&self) -> String {
        String::from_utf8_lossy(&self.value).to_string()
    }

    /// Check if this entry has a lease
    pub fn has_lease(&self) -> bool {
        self.lease_id.is_some()
    }
}


/// Range of keys for scan operations
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct KeyRange {
    /// Start key (inclusive)
    pub start: Vec<u8>,
    /// End key (exclusive). If None, scan single key or to end
    pub end: Option<Vec<u8>>,
}

impl KeyRange {
    /// Create a range for a single key
    pub fn key(key: impl Into<Vec<u8>>) -> Self {
        Self {
            start: key.into(),
            end: None,
        }
    }

    /// Create a range from start to end (exclusive)
    pub fn range(start: impl Into<Vec<u8>>, end: impl Into<Vec<u8>>) -> Self {
        Self {
            start: start.into(),
            end: Some(end.into()),
        }
    }

    /// Create a prefix range (all keys with given prefix)
    pub fn prefix(prefix: impl Into<Vec<u8>>) -> Self {
        let prefix = prefix.into();
        let end = prefix_end(&prefix);
        Self {
            start: prefix,
            end: Some(end),
        }
    }

    /// Check if this range matches a single key
    pub fn is_single_key(&self) -> bool {
        self.end.is_none()
    }
}

/// Calculate the end key for a prefix scan
/// For prefix "abc", returns "abd" (increment last byte)
fn prefix_end(prefix: &[u8]) -> Vec<u8> {
    let mut end = prefix.to_vec();
    for i in (0..end.len()).rev() {
        if end[i] < 0xff {
            end[i] += 1;
            end.truncate(i + 1);
            return end;
        }
    }
    // All bytes are 0xff, return empty to indicate no upper bound
    Vec::new()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_kv_entry_new() {
        let entry = KvEntry::new(b"key".to_vec(), b"value".to_vec(), 1);

        assert_eq!(entry.key, b"key");
        assert_eq!(entry.value, b"value");
        assert_eq!(entry.create_revision, 1);
        assert_eq!(entry.mod_revision, 1);
        assert_eq!(entry.version, 1);
        assert!(entry.lease_id.is_none());
    }

    #[test]
    fn test_kv_entry_update() {
        let entry = KvEntry::new(b"key".to_vec(), b"value1".to_vec(), 1);
        let updated = entry.update(b"value2".to_vec(), 5);

        assert_eq!(updated.key, b"key");
        assert_eq!(updated.value, b"value2");
        assert_eq!(updated.create_revision, 1); // Unchanged
        assert_eq!(updated.mod_revision, 5);
        assert_eq!(updated.version, 2);
    }

    #[test]
    fn test_prefix_end() {
        assert_eq!(prefix_end(b"abc"), b"abd");
        assert_eq!(prefix_end(b"ab\xff"), b"ac");
        assert_eq!(prefix_end(b"\xff\xff"), Vec::<u8>::new());
    }

    #[test]
    fn test_key_range_prefix() {
        let range = KeyRange::prefix("/nodes/");

        assert_eq!(range.start, b"/nodes/");
        assert_eq!(range.end, Some(b"/nodes0".to_vec())); // '/' + 1 = '0'
    }

    #[test]
    fn test_kv_serialization() {
        let entry = KvEntry::new(b"test".to_vec(), b"data".to_vec(), 42);

        let serialized = bincode::serialize(&entry).unwrap();
        let deserialized: KvEntry = bincode::deserialize(&serialized).unwrap();

        assert_eq!(entry, deserialized);
    }
}
