//! Core interface for exchanging data with LevelDB.
use super::bytes::Bytes;

/// Slice is the core interface for exchanging data with LevelDB.
///
/// Slice can exist in one of two states:
/// - Borrowed: References a byte array
/// - Owned: Owns LevelDB-allocated byte data
///
/// # Data Access
///
/// Use the [`as_bytes()`](Slice::as_bytes) method to obtain a reference to the internal data.
///
/// # Important: Iterator Lifetime Warning
///
/// When a Slice is returned from an iterator, it **only holds a reference to LevelDB's internal data**.
/// After the iterator continues iteration (calling next(), seek(), etc.),  the data references
/// in previously returned Slices may become invalid. If you need longer ownership, consider copying the data:
///
/// # Memory Management
///
/// - Borrowed state: Slice does not own data, lifetime must not exceed original data
/// - Owned state: Slice owns LevelDB-allocated memory and automatically frees it on Drop
pub struct Slice<'a> {
    inner: SliceInner<'a>,
}

enum SliceInner<'a> {
    Borrowed(&'a [u8]),
    Owned(Bytes),
}

impl<'a> From<&'a [u8]> for Slice<'a> {
    /// Create a Slice from a byte slice.
    ///
    /// This constructor is intended for users to create Slice instances from their own data.
    /// The Slice will borrow the data, so the original data must outlive the Slice.
    ///
    /// Use this when your own byte data needs to be passed to LevelDB operations
    /// like put(), delete(), or get(). The Slice will only hold a reference, avoiding data copying.
    fn from(data: &'a [u8]) -> Self {
        Slice {
            inner: SliceInner::Borrowed(data),
        }
    }
}

impl From<Bytes> for Slice<'static> {
    /// Create a Slice from LevelDB-allocated bytes.
    ///
    /// This is used internally to wrap data that LevelDB allocates and returns to the
    /// Rust layer. The Slice becomes responsible for managing the memory and ensuring
    /// it's properly freed when no longer needed.
    fn from(bytes: Bytes) -> Self {
        Slice {
            inner: SliceInner::Owned(bytes),
        }
    }
}

impl<'a> std::fmt::Debug for Slice<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Slice({:?})", self.as_bytes())
    }
}

impl<'a> PartialEq for Slice<'a> {
    fn eq(&self, other: &Self) -> bool {
        self.as_bytes() == other.as_bytes()
    }
}

impl<'a> Eq for Slice<'a> {}

impl<'a> PartialOrd for Slice<'a> {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl<'a> Ord for Slice<'a> {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.as_bytes().cmp(other.as_bytes())
    }
}

impl<'a> Slice<'a> {
    /// Get a byte slice reference to the internal data.
    ///
    /// # Returns
    ///
    /// Returns a `&[u8]` reference to the internal data. Regardless of whether the Slice
    /// is in Borrowed or Owned state, you can access the actual data content through this method.
    ///
    /// # Important Lifetime Warning
    ///
    /// **Critical**: If this Slice comes from an iterator, the returned reference's lifetime
    /// is limited by the iterator's state. This reference may become invalid after the iterator
    /// continues iteration.
    pub fn as_bytes(&self) -> &[u8] {
        match &self.inner {
            SliceInner::Borrowed(data) => data,
            SliceInner::Owned(bytes) => bytes.as_ref(),
        }
    }
}

//
// Useful methods when comparing with other types of data
//

impl<'a> PartialEq<Vec<u8>> for Slice<'a> {
    fn eq(&self, other: &Vec<u8>) -> bool {
        self.as_bytes() == other.as_slice()
    }
}

impl<'a> PartialEq<&[u8]> for Slice<'a> {
    fn eq(&self, other: &&[u8]) -> bool {
        self.as_bytes() == *other
    }
}

impl<'a> PartialEq<Slice<'a>> for Vec<u8> {
    fn eq(&self, other: &Slice<'a>) -> bool {
        self.as_slice() == other.as_bytes()
    }
}

impl<'a> PartialEq<Slice<'a>> for &[u8] {
    fn eq(&self, other: &Slice<'a>) -> bool {
        *self == other.as_bytes()
    }
}

impl<const N: usize> PartialEq<[u8; N]> for Slice<'_> {
    fn eq(&self, other: &[u8; N]) -> bool {
        self.as_bytes() == other.as_slice()
    }
}

impl<const N: usize> PartialEq<Slice<'_>> for [u8; N] {
    fn eq(&self, other: &Slice<'_>) -> bool {
        self.as_slice() == other.as_bytes()
    }
}
