use crate::index::{
    config::{IndexTypeUnwrap, IndexTypeWrap},
    tree::nodes::Value,
};
use std::vec::IntoIter;

/// Iterator of values relative to an index key
/// use by get and range functions
///
/// # Example
/// ```rust
/// # use persy::{ValueMode, OpenOptions};
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// # let persy = OpenOptions::new().memory()?;
/// # let mut tx = persy.begin()?;
/// # tx.create_index::<u8,u8>("my_new_index", ValueMode::Cluster)?;
/// # tx.put::<u8,u8>("my_new_index",10,10)?;
/// # let prepared = tx.prepare()?;
/// # prepared.commit()?;
/// let values = persy.get::<u8,u8>("my_new_index",&10)?;
/// for value in values {
///     //...
/// }
/// # Ok(())
/// # }
/// ```
pub struct ValueIter<V> {
    value: Option<IntoIter<V>>,
}

impl<V> From<Value<V::Wrapper>> for ValueIter<V>
where
    V: IndexTypeWrap,
    V::Wrapper: IndexTypeUnwrap<Wrapped = V>,
{
    fn from(val: Value<V::Wrapper>) -> Self {
        ValueIter {
            value: Some(val.into_iter().map(|v| v.unwrap()).collect::<Vec<_>>().into_iter()),
        }
    }
}

impl<V> From<Option<Value<V::Wrapper>>> for ValueIter<V>
where
    V: IndexTypeWrap,
    V::Wrapper: IndexTypeUnwrap<Wrapped = V>,
{
    fn from(val: Option<Value<V::Wrapper>>) -> Self {
        ValueIter {
            value: val.map(|v| v.into_iter().map(|uv| uv.unwrap()).collect::<Vec<_>>().into_iter()),
        }
    }
}

impl<V> Iterator for ValueIter<V> {
    type Item = V;
    fn next(&mut self) -> Option<Self::Item> {
        match &mut self.value {
            Some(i) => i.next(),
            None => None,
        }
    }
}

impl<V> ExactSizeIterator for ValueIter<V> {
    fn len(&self) -> usize {
        match &self.value {
            Some(i) => i.len(),
            None => 0,
        }
    }
}

impl<V> DoubleEndedIterator for ValueIter<V> {
    fn next_back(&mut self) -> Option<Self::Item> {
        match &mut self.value {
            Some(i) => i.next_back(),
            None => None,
        }
    }
}
