use std::borrow::Cow;
use std::io::{ErrorKind, Write};
use ordered_varint::Variable;
use crate::key::{
    ByteSource, CompositeKeyError, CompositeKind, Key, KeyEncoding, KeyVisitor, NextValueError,
};
#[deprecated = "use `CompositeKeyEncoder` instead. This function does not properly sort variable length encoded fields. See #240."]
pub fn encode_composite_field<'k, K: Key<'k>, T: KeyEncoding<K>, Bytes: Write>(
    value: &'k T,
    bytes: &mut Bytes,
) -> Result<(), CompositeKeyError> {
    let t2 = T::as_ord_bytes(value).map_err(CompositeKeyError::new)?;
    if T::LENGTH.is_none() {
        (t2.len() as u64)
            .encode_variable(&mut *bytes)
            .map_err(CompositeKeyError::new)?;
    }
    bytes.write_all(&t2)?;
    Ok(())
}
#[deprecated = "use `CompositeKeyDecoder` instead. This function does not properly sort variable length encoded fields. See #240."]
pub fn decode_composite_field<'a, 'k, T: Key<'k>>(
    mut bytes: &'a [u8],
) -> Result<(T, &'a [u8]), CompositeKeyError> {
    let length = if let Some(length) = T::LENGTH {
        length
    } else {
        usize::try_from(u64::decode_variable(&mut bytes)?)?
    };
    let (t2, remaining) = bytes.split_at(length);
    Ok((
        T::from_ord_bytes(ByteSource::Ephemeral(t2)).map_err(CompositeKeyError::new)?,
        remaining,
    ))
}
#[derive(Debug, Clone)]
#[deprecated = "This type preserves a version of tuple encoding for backwards compatibility. It it is known to have improper key ordering. See https://github.com/khonsulabs/bonsaidb/issues/240."]
pub struct TupleEncodingV1<T>(pub T);
macro_rules! count_args {
    () => (0usize);
    ( $arg:tt $($remaining:tt)* ) => (1usize + count_args!($($remaining)*));
}
macro_rules! impl_key_for_tuple_v1 {
    ($(($index:tt, $varname:ident, $generic:ident)),+) => {
        #[allow(deprecated)]
        impl<'k, $($generic),+> Key<'k> for TupleEncodingV1<($($generic),+,)>
        where
            $($generic: for<'ke> Key<'ke>),+
        {
            const CAN_OWN_BYTES: bool = false;
            fn from_ord_bytes<'e>(bytes: ByteSource<'k, 'e>) -> Result<Self, Self::Error> {
                let bytes = bytes.as_ref();
                $(let ($varname, bytes) = decode_composite_field::<$generic>(bytes)?;)+
                if bytes.is_empty() {
                    Ok(Self(($($varname),+,)))
                } else {
                    Err(CompositeKeyError::new(std::io::Error::from(
                        ErrorKind::InvalidData,
                    )))
                }
            }
        }
        #[allow(deprecated)]
        impl<$($generic),+> KeyEncoding<Self> for TupleEncodingV1<($($generic),+,)>
        where
            $($generic: for<'k> Key<'k>),+
        {
            type Error = CompositeKeyError;
            const LENGTH: Option<usize> = match ($($generic::LENGTH),+,) {
                ($(Some($varname)),+,) => Some($($varname +)+ 0),
                _ => None,
            };
            fn describe<Visitor>(visitor: &mut Visitor)
            where
                Visitor: KeyVisitor,
            {
                visitor.visit_composite(CompositeKind::Tuple, count_args!($($generic)+));
                $($generic::describe(visitor);)+
            }
            fn as_ord_bytes(&self) -> Result<Cow<'_, [u8]>, Self::Error> {
                let mut bytes = Vec::new();
                $(encode_composite_field(&self.0.$index, &mut bytes)?;)+
                Ok(Cow::Owned(bytes))
            }
        }
    };
}
impl_key_for_tuple_v1!((0, t1, T1));
impl_key_for_tuple_v1!((0, t1, T1), (1, t2, T2));
impl_key_for_tuple_v1!((0, t1, T1), (1, t2, T2), (2, t3, T3));
impl_key_for_tuple_v1!((0, t1, T1), (1, t2, T2), (2, t3, T3), (3, t4, T4));
impl_key_for_tuple_v1!(
    (0, t1, T1),
    (1, t2, T2),
    (2, t3, T3),
    (3, t4, T4),
    (4, t5, T5)
);
impl_key_for_tuple_v1!(
    (0, t1, T1),
    (1, t2, T2),
    (2, t3, T3),
    (3, t4, T4),
    (4, t5, T5),
    (5, t6, T6)
);
impl_key_for_tuple_v1!(
    (0, t1, T1),
    (1, t2, T2),
    (2, t3, T3),
    (3, t4, T4),
    (4, t5, T5),
    (5, t6, T6),
    (6, t7, T7)
);
impl_key_for_tuple_v1!(
    (0, t1, T1),
    (1, t2, T2),
    (2, t3, T3),
    (3, t4, T4),
    (4, t5, T5),
    (5, t6, T6),
    (6, t7, T7),
    (7, t8, T8)
);
#[derive(Clone, Debug, Copy, Eq, PartialEq)]
#[deprecated = "this type should not be used in new code and should only be used in transitionary code."]
#[allow(deprecated)]
pub struct OptionKeyV1<T>(pub Option<T>);
#[allow(deprecated)]
impl<'k, T> Key<'k> for OptionKeyV1<T>
where
    T: Key<'k>,
    Self: KeyEncoding<Self, Error = <T as KeyEncoding<T>>::Error>,
{
    const CAN_OWN_BYTES: bool = false;
    fn from_ord_bytes<'b>(bytes: ByteSource<'k, 'b>) -> Result<Self, Self::Error> {
        if bytes.as_ref().is_empty() {
            Ok(Self(None))
        } else {
            Ok(Self(Some(T::from_ord_bytes(bytes)?)))
        }
    }
    fn first_value() -> Result<Self, NextValueError> {
        Ok(Self(Some(T::first_value()?)))
    }
    fn next_value(&self) -> Result<Self, NextValueError> {
        self.0.as_ref().map(T::next_value).transpose().map(Self)
    }
}
#[allow(deprecated)]
impl<K, T> KeyEncoding<OptionKeyV1<K>> for OptionKeyV1<T>
where
    T: KeyEncoding<K>,
    K: for<'k> Key<'k>,
{
    type Error = T::Error;
    const LENGTH: Option<usize> = T::LENGTH;
    fn describe<Visitor>(visitor: &mut Visitor)
    where
        Visitor: KeyVisitor,
    {
        visitor.visit_composite(CompositeKind::Option, 1);
        T::describe(visitor);
    }
    fn as_ord_bytes(&self) -> Result<Cow<'_, [u8]>, Self::Error> {
        if let Some(contents) = &self.0 {
            let contents = contents.as_ord_bytes()?;
            assert!(!contents.is_empty());
            Ok(contents)
        } else {
            Ok(Cow::default())
        }
    }
}