use std::collections::BTreeMap;
use std::fmt::Debug;
use arc_bytes::serde::Bytes;
use serde::{Deserialize, Serialize};
use crate::document::{CollectionHeader, DocumentId, Header, OwnedDocument};
use crate::schema::view::{self, ByteSource, Key, SerializedView, View, ViewSchema};
use crate::schema::Collection;
#[derive(Eq, PartialEq, Debug)]
pub struct Map<K = (), V = ()> {
    pub source: Header,
    pub key: K,
    pub value: V,
}
impl<K, V> Map<K, V> {
    pub(crate) fn serialized<'a, View>(&self) -> Result<Serialized, view::Error>
    where
        K: Key<'a>,
        View: SerializedView<Value = V>,
    {
        Ok(Serialized {
            source: self.source.clone(),
            key: Bytes::from(
                self.key
                    .as_ord_bytes()
                    .map_err(view::Error::key_serialization)?
                    .to_vec(),
            ),
            value: Bytes::from(View::serialize(&self.value)?),
        })
    }
}
impl<K, V> Map<K, V> {
    pub const fn new(source: Header, key: K, value: V) -> Self {
        Self { source, key, value }
    }
}
#[derive(Eq, PartialEq, Debug)]
pub struct CollectionMap<PrimaryKey, K = (), V = ()> {
    pub source: CollectionHeader<PrimaryKey>,
    pub key: K,
    pub value: V,
}
pub type ViewMappings<V> = Vec<
    CollectionMap<
        <<V as View>::Collection as Collection>::PrimaryKey,
        <V as View>::Key,
        <V as View>::Value,
    >,
>;
#[derive(Debug, Eq, PartialEq)]
#[must_use]
pub enum Mappings<K = (), V = ()> {
    Simple(Option<Map<K, V>>),
    List(Vec<Map<K, V>>),
}
impl<K, V> Default for Mappings<K, V> {
    fn default() -> Self {
        Self::none()
    }
}
impl<K, V> Mappings<K, V> {
    pub const fn none() -> Self {
        Self::Simple(None)
    }
    pub fn push(&mut self, mapping: Map<K, V>) {
        match self {
            Self::Simple(existing_mapping) => {
                *self = if let Some(existing_mapping) = existing_mapping.take() {
                    Self::List(vec![existing_mapping, mapping])
                } else {
                    Self::Simple(Some(mapping))
                };
            }
            Self::List(vec) => vec.push(mapping),
        }
    }
    pub fn and(mut self, mappings: Self) -> Self {
        self.extend(mappings);
        self
    }
    pub fn iter(&self) -> MappingsIter<'_, K, V> {
        self.into_iter()
    }
    pub fn len(&self) -> usize {
        match self {
            Mappings::Simple(None) => 0,
            Mappings::Simple(Some(_)) => 1,
            Mappings::List(v) => v.len(),
        }
    }
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
}
impl<K, V> Extend<Map<K, V>> for Mappings<K, V> {
    fn extend<T: IntoIterator<Item = Map<K, V>>>(&mut self, iter: T) {
        let iter = iter.into_iter();
        for map in iter {
            self.push(map);
        }
    }
}
impl<K, V> FromIterator<Map<K, V>> for Mappings<K, V> {
    fn from_iter<T: IntoIterator<Item = Map<K, V>>>(iter: T) -> Self {
        let mut mappings = Self::none();
        mappings.extend(iter);
        mappings
    }
}
impl<K, V> FromIterator<Self> for Mappings<K, V> {
    fn from_iter<T: IntoIterator<Item = Self>>(iter: T) -> Self {
        let mut iter = iter.into_iter();
        if let Some(mut collected) = iter.next() {
            for mappings in iter {
                collected.extend(mappings);
            }
            collected
        } else {
            Self::none()
        }
    }
}
impl<K, V> IntoIterator for Mappings<K, V> {
    type IntoIter = MappingsIntoIter<K, V>;
    type Item = Map<K, V>;
    fn into_iter(self) -> Self::IntoIter {
        match self {
            Mappings::Simple(option) => MappingsIntoIter::Inline(option),
            Mappings::List(list) => MappingsIntoIter::Vec(list.into_iter()),
        }
    }
}
impl<'a, K, V> IntoIterator for &'a Mappings<K, V> {
    type IntoIter = MappingsIter<'a, K, V>;
    type Item = &'a Map<K, V>;
    fn into_iter(self) -> Self::IntoIter {
        match self {
            Mappings::Simple(option) => MappingsIter::Inline(option.iter()),
            Mappings::List(list) => MappingsIter::Vec(list.iter()),
        }
    }
}
pub enum MappingsIntoIter<K = (), V = ()> {
    Inline(Option<Map<K, V>>),
    Vec(std::vec::IntoIter<Map<K, V>>),
}
impl<K, V> Iterator for MappingsIntoIter<K, V> {
    type Item = Map<K, V>;
    fn next(&mut self) -> Option<Self::Item> {
        match self {
            MappingsIntoIter::Inline(opt) => opt.take(),
            MappingsIntoIter::Vec(iter) => iter.next(),
        }
    }
}
pub enum MappingsIter<'a, K = (), V = ()> {
    Inline(std::option::Iter<'a, Map<K, V>>),
    Vec(std::slice::Iter<'a, Map<K, V>>),
}
impl<'a, K, V> Iterator for MappingsIter<'a, K, V> {
    type Item = &'a Map<K, V>;
    fn next(&mut self) -> Option<Self::Item> {
        match self {
            MappingsIter::Inline(i) => i.next(),
            MappingsIter::Vec(i) => i.next(),
        }
    }
}
pub struct MappedDocuments<D, V: View> {
    pub mappings: ViewMappings<V>,
    pub documents: BTreeMap<<V::Collection as Collection>::PrimaryKey, D>,
}
impl<D, V: View> MappedDocuments<D, V> {
    #[must_use]
    pub fn len(&self) -> usize {
        self.mappings.len()
    }
    #[must_use]
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
    #[must_use]
    #[allow(clippy::missing_panics_doc)]
    pub fn get(&self, index: usize) -> Option<MappedDocument<'_, D, V::Key, V::Value>> {
        if index < self.len() {
            let mapping = &self.mappings[index];
            let document = self
                .documents
                .get(&mapping.source.id)
                .expect("missing mapped document");
            Some(MappedDocument {
                key: &mapping.key,
                value: &mapping.value,
                document,
            })
        } else {
            None
        }
    }
    #[must_use]
    pub const fn iter(&self) -> MappedDocumentsIter<'_, D, V> {
        MappedDocumentsIter {
            docs: self,
            index: 0,
        }
    }
}
impl<D, V: View> Debug for MappedDocuments<D, V>
where
    V::Key: Debug,
    V::Value: Debug,
    D: Debug,
    <V::Collection as Collection>::PrimaryKey: Debug,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("MappedDocuments")
            .field("mappings", &self.mappings)
            .field("documents", &self.documents)
            .finish()
    }
}
pub struct MappedDocumentsIter<'a, D, V: View> {
    docs: &'a MappedDocuments<D, V>,
    index: usize,
}
impl<'a, D, V: View> IntoIterator for &'a MappedDocuments<D, V> {
    type IntoIter = MappedDocumentsIter<'a, D, V>;
    type Item = MappedDocument<'a, D, V::Key, V::Value>;
    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}
impl<'a, D, V: View> Iterator for MappedDocumentsIter<'a, D, V> {
    type Item = MappedDocument<'a, D, V::Key, V::Value>;
    fn next(&mut self) -> Option<Self::Item> {
        let doc = self.docs.get(self.index);
        self.index = self.index.saturating_add(1);
        doc
    }
}
pub struct MappedDocument<'a, D, K, V> {
    pub key: &'a K,
    pub value: &'a V,
    pub document: &'a D,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Serialized {
    pub source: Header,
    pub key: Bytes,
    pub value: Bytes,
}
impl Serialized {
    pub fn deserialized<View: SerializedView>(
        &self,
    ) -> Result<Map<View::Key, View::Value>, view::Error> {
        Ok(Map::new(
            self.source.clone(),
            <View::Key as Key>::from_ord_bytes(ByteSource::Borrowed(&self.key))
                .map_err(view::Error::key_serialization)?,
            View::deserialize(&self.value)?,
        ))
    }
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct MappedSerializedDocuments {
    pub mappings: Vec<Serialized>,
    pub documents: BTreeMap<DocumentId, OwnedDocument>,
}
impl MappedSerializedDocuments {
    pub fn deserialized<View: SerializedView>(
        self,
    ) -> Result<MappedDocuments<OwnedDocument, View>, crate::Error> {
        let mappings = self
            .mappings
            .iter()
            .map(|mapping| {
                let deserialized = Serialized::deserialized::<View>(mapping)?;
                Ok(CollectionMap {
                    source: deserialized.source.try_into()?,
                    key: deserialized.key,
                    value: deserialized.value,
                })
            })
            .collect::<Result<Vec<_>, crate::Error>>()?;
        Ok(MappedDocuments {
            mappings,
            documents: self
                .documents
                .into_iter()
                .map(|(key, value)| {
                    let key = key.deserialize()?;
                    Ok((key, value))
                })
                .collect::<Result<BTreeMap<_, _>, crate::Error>>()?,
        })
    }
}
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct MappedValue<K, V> {
    pub key: K,
    pub value: V,
}
impl<K, V> MappedValue<K, V> {
    pub const fn new(key: K, value: V) -> Self {
        Self { key, value }
    }
}
pub type ViewMappedValue<'doc, V> =
    MappedValue<<V as ViewSchema>::MappedKey<'doc>, <<V as ViewSchema>::View as View>::Value>;
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct MappedSerializedValue {
    pub key: Bytes,
    pub value: Bytes,
}