use crate::{
    arrayvec, ord::iter_cmp, ArrayVec, Decode, DecodeValue, DerOrd, Encode, EncodeValue, FixedTag,
    Header, Length, Reader, Result, Tag, ValueOrd, Writer,
};
use core::cmp::Ordering;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SequenceOf<T, const N: usize> {
    inner: ArrayVec<T, N>,
}
impl<T, const N: usize> SequenceOf<T, N> {
    pub fn new() -> Self {
        Self {
            inner: ArrayVec::new(),
        }
    }
    pub fn add(&mut self, element: T) -> Result<()> {
        self.inner.add(element)
    }
    pub fn get(&self, index: usize) -> Option<&T> {
        self.inner.get(index)
    }
    pub fn iter(&self) -> SequenceOfIter<'_, T> {
        SequenceOfIter {
            inner: self.inner.iter(),
        }
    }
    pub fn is_empty(&self) -> bool {
        self.inner.is_empty()
    }
    pub fn len(&self) -> usize {
        self.inner.len()
    }
}
impl<T, const N: usize> Default for SequenceOf<T, N> {
    fn default() -> Self {
        Self::new()
    }
}
impl<'a, T, const N: usize> DecodeValue<'a> for SequenceOf<T, N>
where
    T: Decode<'a>,
{
    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
        reader.read_nested(header.length, |reader| {
            let mut sequence_of = Self::new();
            while !reader.is_finished() {
                sequence_of.add(T::decode(reader)?)?;
            }
            Ok(sequence_of)
        })
    }
}
impl<T, const N: usize> EncodeValue for SequenceOf<T, N>
where
    T: Encode,
{
    fn value_len(&self) -> Result<Length> {
        self.iter()
            .fold(Ok(Length::ZERO), |len, elem| len + elem.encoded_len()?)
    }
    fn encode_value(&self, writer: &mut dyn Writer) -> Result<()> {
        for elem in self.iter() {
            elem.encode(writer)?;
        }
        Ok(())
    }
}
impl<T, const N: usize> FixedTag for SequenceOf<T, N> {
    const TAG: Tag = Tag::Sequence;
}
impl<T, const N: usize> ValueOrd for SequenceOf<T, N>
where
    T: DerOrd,
{
    fn value_cmp(&self, other: &Self) -> Result<Ordering> {
        iter_cmp(self.iter(), other.iter())
    }
}
#[derive(Clone, Debug)]
pub struct SequenceOfIter<'a, T> {
    inner: arrayvec::Iter<'a, T>,
}
impl<'a, T> Iterator for SequenceOfIter<'a, T> {
    type Item = &'a T;
    fn next(&mut self) -> Option<&'a T> {
        self.inner.next()
    }
}
impl<'a, T> ExactSizeIterator for SequenceOfIter<'a, T> {}
impl<'a, T, const N: usize> DecodeValue<'a> for [T; N]
where
    T: Decode<'a>,
{
    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
        let sequence_of = SequenceOf::<T, N>::decode_value(reader, header)?;
        if sequence_of.inner.len() == N {
            Ok(sequence_of
                .inner
                .into_array()
                .map(|elem| elem.expect("arrayvec length mismatch")))
        } else {
            Err(Self::TAG.length_error())
        }
    }
}
impl<T, const N: usize> EncodeValue for [T; N]
where
    T: Encode,
{
    fn value_len(&self) -> Result<Length> {
        self.iter()
            .fold(Ok(Length::ZERO), |len, elem| len + elem.encoded_len()?)
    }
    fn encode_value(&self, writer: &mut dyn Writer) -> Result<()> {
        for elem in self {
            elem.encode(writer)?;
        }
        Ok(())
    }
}
impl<T, const N: usize> FixedTag for [T; N] {
    const TAG: Tag = Tag::Sequence;
}
impl<T, const N: usize> ValueOrd for [T; N]
where
    T: DerOrd,
{
    fn value_cmp(&self, other: &Self) -> Result<Ordering> {
        iter_cmp(self.iter(), other.iter())
    }
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl<'a, T> DecodeValue<'a> for Vec<T>
where
    T: Decode<'a>,
{
    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
        reader.read_nested(header.length, |reader| {
            let mut sequence_of = Self::new();
            while !reader.is_finished() {
                sequence_of.push(T::decode(reader)?);
            }
            Ok(sequence_of)
        })
    }
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl<T> EncodeValue for Vec<T>
where
    T: Encode,
{
    fn value_len(&self) -> Result<Length> {
        self.iter()
            .fold(Ok(Length::ZERO), |len, elem| len + elem.encoded_len()?)
    }
    fn encode_value(&self, writer: &mut dyn Writer) -> Result<()> {
        for elem in self {
            elem.encode(writer)?;
        }
        Ok(())
    }
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl<T> FixedTag for Vec<T> {
    const TAG: Tag = Tag::Sequence;
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl<T> ValueOrd for Vec<T>
where
    T: DerOrd,
{
    fn value_cmp(&self, other: &Self) -> Result<Ordering> {
        iter_cmp(self.iter(), other.iter())
    }
}