use serde::ser::{Serialize, SerializeSeq, Serializer};

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub(crate) struct MiniVec<T: Copy, const N: usize> {
    items: [Option<T>; N],
    len: usize,
}

impl<T: Copy, const N: usize> MiniVec<T, N> {
    pub(crate) const fn new() -> Self {
        Self {
            items: [None; N],
            len: 0,
        }
    }

    pub(crate) const fn len(&self) -> usize {
        self.len
    }

    #[allow(unused)]
    pub(crate) const fn is_empty(&self) -> bool {
        self.len == 0
    }

    pub(crate) const fn is_full(&self) -> bool {
        self.len() == self.capacity()
    }

    pub(crate) const fn capacity(&self) -> usize {
        N
    }

    pub(crate) const fn push(&mut self, item: T) {
        assert!(self.len < N, "MiniVec overflow");
        self.items[self.len] = Some(item);
        self.len += 1;
    }

    #[allow(unused)]
    pub(crate) const fn get(&self, index: usize) -> Option<T> {
        if index < self.len {
            self.items[index]
        } else {
            None
        }
    }

    // Note: `iter()` cannot be const yet, because `Iterator` trait isn't const
    pub(crate) fn iter(&self) -> impl Iterator<Item = T> + '_ {
        self.items[..self.len]
            .iter()
            .map(|&x| x.expect("invalid MiniVec"))
    }
}

impl<T: Copy + Serialize, const N: usize> Serialize for MiniVec<T, N> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut seq = serializer.serialize_seq(Some(self.len))?;
        for i in 0..self.len {
            if let Some(v) = self.items[i] {
                seq.serialize_element(&v)?;
            }
        }
        seq.end()
    }
}

impl<T: Copy, const N: usize> FromIterator<T> for MiniVec<T, N> {
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
        let mut result = Self::new();
        for item in iter {
            if result.is_full() {
                break;
            } else {
                result.push(item);
            }
        }
        result
    }
}

#[cfg(feature = "schemars")]
mod jsonschema_impl {
    use std::borrow::Cow;

    use schemars::{JsonSchema, Schema, SchemaGenerator};

    use crate::minivec::MiniVec;

    impl<T: JsonSchema + Copy, const N: usize> JsonSchema for MiniVec<T, N> {
        fn schema_name() -> Cow<'static, str> {
            format!("MiniVec_{}_{}", T::schema_name(), N).into()
        }

        fn json_schema(gen_: &mut SchemaGenerator) -> Schema {
            gen_.subschema_for::<Vec<T>>()
        }
    }
}

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

    #[test]
    fn test_new() {
        let vec: MiniVec<i32, 5> = MiniVec::new();
        assert_eq!(vec.len(), 0);
        assert!(vec.is_empty());
        assert_eq!(vec.capacity(), 5);
    }

    #[test]
    fn test_push() {
        let mut vec: MiniVec<i32, 3> = MiniVec::new();
        vec.push(1);
        assert_eq!(vec.len(), 1);
        assert!(!vec.is_empty());

        vec.push(2);
        assert_eq!(vec.len(), 2);

        vec.push(3);
        assert_eq!(vec.len(), 3);
        assert!(vec.is_full());
    }

    #[test]
    #[should_panic(expected = "MiniVec overflow")]
    fn test_push_overflow() {
        let mut vec: MiniVec<i32, 2> = MiniVec::new();
        vec.push(1);
        vec.push(2);
        vec.push(3); // Should panic
    }

    #[test]
    fn test_get() {
        let mut vec: MiniVec<i32, 5> = MiniVec::new();
        vec.push(10);
        vec.push(20);
        vec.push(30);

        assert_eq!(vec.get(0), Some(10));
        assert_eq!(vec.get(1), Some(20));
        assert_eq!(vec.get(2), Some(30));
        assert_eq!(vec.get(3), None);
        assert_eq!(vec.get(100), None);
    }

    #[test]
    fn test_is_empty() {
        let mut vec: MiniVec<i32, 3> = MiniVec::new();
        assert!(vec.is_empty());

        vec.push(1);
        assert!(!vec.is_empty());
    }

    #[test]
    fn test_is_full() {
        let mut vec: MiniVec<i32, 2> = MiniVec::new();
        assert!(!vec.is_full());

        vec.push(1);
        assert!(!vec.is_full());

        vec.push(2);
        assert!(vec.is_full());
    }

    #[test]
    fn test_capacity() {
        let vec: MiniVec<i32, 5> = MiniVec::new();
        assert_eq!(vec.capacity(), 5);

        let vec: MiniVec<i32, 100> = MiniVec::new();
        assert_eq!(vec.capacity(), 100);
    }

    #[test]
    fn test_iter() {
        let mut vec: MiniVec<i32, 5> = MiniVec::new();
        vec.push(1);
        vec.push(2);
        vec.push(3);

        let collected: Vec<i32> = vec.iter().collect();
        assert_eq!(collected, vec![1, 2, 3]);
    }

    #[test]
    fn test_iter_empty() {
        let vec: MiniVec<i32, 5> = MiniVec::new();
        let collected: Vec<i32> = vec.iter().collect();
        assert_eq!(collected.len(), 0);
    }

    #[test]
    fn test_from_iterator() {
        let source = vec![1, 2, 3, 4, 5];
        let vec: MiniVec<i32, 10> = source.into_iter().collect();

        assert_eq!(vec.len(), 5);
        assert_eq!(vec.get(0), Some(1));
        assert_eq!(vec.get(4), Some(5));
    }

    #[test]
    fn test_from_iterator_truncates() {
        let source = vec![1, 2, 3, 4, 5, 6, 7, 8];
        let vec: MiniVec<i32, 5> = source.into_iter().collect();

        // Should only collect the first 5 items
        assert_eq!(vec.len(), 5);
        assert!(vec.is_full());
        assert_eq!(vec.get(0), Some(1));
        assert_eq!(vec.get(4), Some(5));
        assert_eq!(vec.get(5), None);
    }

    #[test]
    fn test_copy_and_clone() {
        let mut vec: MiniVec<i32, 3> = MiniVec::new();
        vec.push(1);
        vec.push(2);

        // Test Copy
        let vec2 = vec;
        assert_eq!(vec.len(), vec2.len());
        assert_eq!(vec.get(0), vec2.get(0));

        // Test Clone
        let vec3 = vec.clone();
        assert_eq!(vec.len(), vec3.len());
        assert_eq!(vec.get(1), vec3.get(1));
    }

    #[test]
    fn test_with_different_types() {
        // Test with char
        let mut vec: MiniVec<char, 3> = MiniVec::new();
        vec.push('a');
        vec.push('b');
        assert_eq!(vec.get(0), Some('a'));
        assert_eq!(vec.get(1), Some('b'));

        // Test with f64
        let mut vec: MiniVec<f64, 2> = MiniVec::new();
        vec.push(1.5);
        vec.push(2.5);
        assert_eq!(vec.get(0), Some(1.5));
        assert_eq!(vec.get(1), Some(2.5));
    }
}
