use crate::core::storage::arc_str::ArcStr;
use bytemuck::{Pod, Zeroable};
use iter_enum::{
    DoubleEndedIterator, ExactSizeIterator, FusedIterator, IndexedParallelIterator, Iterator,
    ParallelExtend, ParallelIterator,
};
use rayon::prelude::*;
use serde::{Deserialize, Serialize};
use std::{
    fmt::{Display, Formatter, Result as FmtResult},
    iter::Copied,
    sync::Arc,
};

#[derive(
    Debug,
    Default,
    Copy,
    Clone,
    PartialEq,
    Eq,
    Ord,
    PartialOrd,
    Hash,
    Serialize,
    Deserialize,
    Pod,
    Zeroable,
)]
#[repr(transparent)]
pub struct LayerId(pub usize);
impl PartialEq<usize> for LayerId {
    fn eq(&self, other: &usize) -> bool {
        self.0 == *other
    }
}

impl PartialEq<LayerId> for usize {
    fn eq(&self, other: &LayerId) -> bool {
        *self == other.0
    }
}

impl Display for LayerId {
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        Display::fmt(&self.0, f)
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Layer {
    All,
    None,
    Default,
    One(ArcStr),
    Multiple(Arc<[ArcStr]>),
}

impl Layer {
    pub fn contains(&self, name: &str) -> bool {
        match self {
            Layer::All => true,
            Layer::None => false,
            Layer::Default => name == "_default",
            Layer::One(layer) => layer == name,
            Layer::Multiple(layers) => layers.iter().any(|l| l == name),
        }
    }

    fn from_iter<I: IntoIterator<Item: SingleLayer, IntoIter: ExactSizeIterator>>(
        names: I,
    ) -> Self {
        let mut names = names.into_iter();
        match names.len() {
            0 => Layer::None,
            1 => Layer::One(names.next().unwrap().name()),
            _ => Layer::Multiple(names.map(|s| s.name()).collect::<Vec<_>>().into()),
        }
    }
}

pub trait SingleLayer {
    fn name(self) -> ArcStr;
}

impl<T: SingleLayer> From<T> for Layer {
    fn from(value: T) -> Self {
        Layer::One(value.name())
    }
}

impl SingleLayer for ArcStr {
    fn name(self) -> ArcStr {
        self
    }
}

impl SingleLayer for String {
    fn name(self) -> ArcStr {
        self.into()
    }
}
impl SingleLayer for &str {
    fn name(self) -> ArcStr {
        self.into()
    }
}

impl SingleLayer for &String {
    fn name(self) -> ArcStr {
        self.as_str().into()
    }
}

impl SingleLayer for &ArcStr {
    fn name(self) -> ArcStr {
        self.clone()
    }
}

impl<T: SingleLayer> SingleLayer for Option<T> {
    fn name(self) -> ArcStr {
        match self {
            None => ArcStr::from("_default"),
            Some(s) => s.name(),
        }
    }
}

impl<T: SingleLayer> From<Vec<T>> for Layer {
    fn from(names: Vec<T>) -> Self {
        Self::from_iter(names)
    }
}

impl<T: SingleLayer, const N: usize> From<[T; N]> for Layer {
    fn from(names: [T; N]) -> Self {
        Self::from_iter(names)
    }
}

impl<'a, T: 'a> From<&'a [T]> for Layer
where
    &'a T: SingleLayer,
{
    fn from(names: &'a [T]) -> Self {
        Self::from_iter(names)
    }
}

impl<'a, T: 'a> From<&'a Vec<T>> for Layer
where
    &'a T: SingleLayer,
{
    fn from(names: &'a Vec<T>) -> Self {
        Self::from_iter(names)
    }
}

#[derive(Clone, Debug)]
pub enum LayerIds {
    None,
    All,
    One(LayerId),
    Multiple(Multiple),
}

#[derive(
    Iterator,
    DoubleEndedIterator,
    ExactSizeIterator,
    FusedIterator,
    ParallelIterator,
    ParallelExtend,
    IndexedParallelIterator,
)]
pub enum LayerVariants<None, All, One, Multiple> {
    None(None),
    All(All),
    One(One),
    Multiple(Multiple),
}

#[derive(Clone, Debug, Default)]
pub struct Multiple(pub Arc<[LayerId]>);

impl<'a> IntoIterator for &'a Multiple {
    type Item = LayerId;
    type IntoIter = Copied<core::slice::Iter<'a, Self::Item>>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.iter().copied()
    }
}

impl Multiple {
    #[inline]
    pub fn contains(&self, id: LayerId) -> bool {
        self.0.binary_search(&id).is_ok()
    }

    #[inline]
    pub fn into_iter(self) -> impl Iterator<Item = LayerId> {
        let ids = self.0.clone();
        (0..ids.len()).map(move |i| ids[i])
    }

    #[inline]
    pub fn iter(&self) -> impl Iterator<Item = LayerId> + '_ {
        self.0.iter().copied()
    }

    #[inline]
    pub fn get_id_by_index(&self, index: usize) -> Option<LayerId> {
        self.0.get(index).copied()
    }

    #[inline]
    pub fn get_index_by_id(&self, id: LayerId) -> Option<usize> {
        self.0.binary_search(&id).ok()
    }

    #[inline]
    pub fn par_iter(&self) -> impl rayon::iter::ParallelIterator<Item = LayerId> {
        let bit_vec = self.0.clone();
        (0..bit_vec.len()).into_par_iter().map(move |i| bit_vec[i])
    }

    #[inline]
    pub fn len(&self) -> usize {
        self.0.len()
    }

    #[inline]
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }
}

impl FromIterator<usize> for Multiple {
    fn from_iter<I: IntoIterator<Item = usize>>(iter: I) -> Self {
        let mut inner: Vec<_> = iter.into_iter().map(LayerId).collect();
        inner.sort();
        inner.dedup();
        Multiple(inner.into())
    }
}

impl FromIterator<LayerId> for Multiple {
    fn from_iter<I: IntoIterator<Item = LayerId>>(iter: I) -> Self {
        let mut inner: Vec<_> = iter.into_iter().collect();
        inner.sort();
        inner.dedup();
        Multiple(inner.into())
    }
}

impl From<Vec<LayerId>> for Multiple {
    fn from(mut v: Vec<LayerId>) -> Self {
        v.sort();
        v.dedup();
        Multiple(v.into())
    }
}

impl From<Vec<usize>> for Multiple {
    fn from(v: Vec<usize>) -> Self {
        let mut v: Vec<_> = v.into_iter().map(LayerId).collect();
        v.sort();
        v.dedup();
        Multiple(v.into())
    }
}
