//! Key matching utilities for watch subscriptions

/// Key matcher for watch subscriptions
#[derive(Debug, Clone)]
pub struct KeyMatcher {
    /// Start key
    key: Vec<u8>,
    /// Range end (exclusive). None = single key match
    range_end: Option<Vec<u8>>,
}

impl KeyMatcher {
    /// Create a matcher for a single key
    pub fn key(key: impl Into<Vec<u8>>) -> Self {
        Self {
            key: key.into(),
            range_end: None,
        }
    }

    /// Create a matcher for a key range
    pub fn range(key: impl Into<Vec<u8>>, range_end: impl Into<Vec<u8>>) -> Self {
        Self {
            key: key.into(),
            range_end: Some(range_end.into()),
        }
    }

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

    /// Create a matcher for all keys
    pub fn all() -> Self {
        Self {
            key: vec![0],
            range_end: Some(vec![]),
        }
    }

    /// Check if a key matches this matcher
    pub fn matches(&self, target: &[u8]) -> bool {
        match &self.range_end {
            None => self.key == target,
            Some(end) => {
                if end.is_empty() {
                    // Empty end means all keys >= start
                    target >= self.key.as_slice()
                } else {
                    target >= self.key.as_slice() && target < end.as_slice()
                }
            }
        }
    }

    /// Get the start key
    pub fn start_key(&self) -> &[u8] {
        &self.key
    }

    /// Get the range end
    pub fn range_end(&self) -> Option<&[u8]> {
        self.range_end.as_deref()
    }

    /// Check if this is a single key match
    pub fn is_single_key(&self) -> bool {
        self.range_end.is_none()
    }

    /// Check if this is a prefix match
    pub fn is_prefix(&self) -> bool {
        self.range_end.is_some()
    }
}

/// 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_single_key_match() {
        let matcher = KeyMatcher::key(b"/nodes/1");

        assert!(matcher.matches(b"/nodes/1"));
        assert!(!matcher.matches(b"/nodes/2"));
        assert!(!matcher.matches(b"/nodes/10"));
        assert!(!matcher.matches(b"/nodes"));
    }

    #[test]
    fn test_prefix_match() {
        let matcher = KeyMatcher::prefix(b"/nodes/");

        assert!(matcher.matches(b"/nodes/1"));
        assert!(matcher.matches(b"/nodes/abc"));
        assert!(matcher.matches(b"/nodes/"));
        assert!(!matcher.matches(b"/nodes"));
        assert!(!matcher.matches(b"/tasks/1"));
    }

    #[test]
    fn test_range_match() {
        let matcher = KeyMatcher::range(b"a", b"d");

        assert!(matcher.matches(b"a"));
        assert!(matcher.matches(b"b"));
        assert!(matcher.matches(b"c"));
        assert!(!matcher.matches(b"d")); // End is exclusive
        assert!(!matcher.matches(b"e"));
    }

    #[test]
    fn test_all_match() {
        let matcher = KeyMatcher::all();

        assert!(matcher.matches(b"any"));
        assert!(matcher.matches(b"/path/to/key"));
        assert!(matcher.matches(b"\xff\xff\xff"));
    }

    #[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"a\xff\xff"), b"b");
        assert_eq!(prefix_end(b"\xff\xff"), Vec::<u8>::new());
    }
}
