Documentation
use crate::{parse::component_value::ComponentValue, token::stream::CopyableTokenStream};

use super::{
    known::{IsKnownCollection, IsKnownCollectionWithConstEmpty},
    parsed_value_list::KnownParsedValueList,
    FilterOutWhitespace,
};

#[non_exhaustive]
pub struct KnownComponentValueList<'a, V: IsKnownComponentValueList<'a>> {
    value_list: KnownParsedValueList<'a, V::Collection, ComponentValue<'a>>,
}

impl<'a, V: IsKnownComponentValueList<'a>> KnownComponentValueList<'a, V> {
    pub(crate) const fn full(&self) -> CopyableTokenStream<'a> {
        self.value_list.full()
    }

    pub(crate) const fn full_as_str(&self) -> &'a str {
        self.value_list.full_as_str()
    }

    pub const fn as_known_parsed_value_list(
        &self,
    ) -> &KnownParsedValueList<'a, V::Collection, ComponentValue<'a>> {
        &self.value_list
    }
}

impl<'a, V: IsKnownComponentValueListWithConstEmpty<'a>> KnownComponentValueList<'a, V> {
    pub(crate) const EMPTY: Self = Self {
        value_list: KnownParsedValueList::EMPTY,
    };
}

impl<'a, V: IsKnownComponentValueList<'a>> Copy for KnownComponentValueList<'a, V> {}
impl<'a, V: IsKnownComponentValueList<'a>> Clone for KnownComponentValueList<'a, V> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<'a, V: IsKnownComponentValueList<'a>> std::fmt::Debug for KnownComponentValueList<'a, V> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("KnownComponentValueList")
            .field("value_list", &self.value_list)
            .finish()
    }
}

mod sealed {
    pub trait IsKnownComponentValueList<'a> {}
}

pub trait IsKnownComponentValueList<'a>: sealed::IsKnownComponentValueList<'a> {
    type Collection: IsKnownCollection<ComponentValue<'a>>;

    const FILTER_OUT_WHITESPACE: bool;
}

pub trait IsKnownComponentValueListWithConstEmpty<'a>:
    IsKnownComponentValueList<'a, Collection = Self::CollectionWithConstEmpty>
{
    type CollectionWithConstEmpty: IsKnownCollectionWithConstEmpty<ComponentValue<'a>>;
    const EMPTY_AS_KNOWN_COMPONENT_VALUE_LIST: KnownComponentValueList<'a, Self::Collection>;
}

impl<'a, L: IsKnownCollection<ComponentValue<'a>>> sealed::IsKnownComponentValueList<'a> for L {}
impl<'a, L: IsKnownCollection<ComponentValue<'a>>> IsKnownComponentValueList<'a> for L {
    type Collection = L;
    const FILTER_OUT_WHITESPACE: bool = false;
}
impl<'a, L: IsKnownCollectionWithConstEmpty<ComponentValue<'a>>>
    IsKnownComponentValueListWithConstEmpty<'a> for L
{
    type CollectionWithConstEmpty = Self::Collection;
    const EMPTY_AS_KNOWN_COMPONENT_VALUE_LIST: KnownComponentValueList<'a, Self> =
        KnownComponentValueList {
            value_list: KnownParsedValueList::EMPTY,
        };
}

impl<'a, L: IsKnownCollection<ComponentValue<'a>>> sealed::IsKnownComponentValueList<'a>
    for FilterOutWhitespace<L>
{
}
impl<'a, L: IsKnownCollection<ComponentValue<'a>>> IsKnownComponentValueList<'a>
    for FilterOutWhitespace<L>
{
    type Collection = L;
    const FILTER_OUT_WHITESPACE: bool = true;
}
impl<'a, L: IsKnownCollectionWithConstEmpty<ComponentValue<'a>>>
    IsKnownComponentValueListWithConstEmpty<'a> for FilterOutWhitespace<L>
{
    type CollectionWithConstEmpty = Self::Collection;
    const EMPTY_AS_KNOWN_COMPONENT_VALUE_LIST: KnownComponentValueList<'a, Self::Collection> =
        L::EMPTY_AS_KNOWN_COMPONENT_VALUE_LIST;
}

pub(crate) mod builder {
    use crate::{
        collections::{
            array_vec::ArrayVec,
            known::IsKnownCollectionWithConstEmpty,
            lead_vec::LeadVec,
            parsed_value_list::{KnownParsedValueList, KnownParsedValueListBuilder},
        },
        parse::component_value::ComponentValue,
        token::stream::CopyableTokenStream,
    };

    use super::{
        IsKnownComponentValueList, IsKnownComponentValueListWithConstEmpty, KnownComponentValueList,
    };
    impl<'a, V: IsKnownComponentValueList<'a>> KnownComponentValueList<'a, V> {
        pub(crate) const fn start_builder() -> KnownComponentValueListBuilder<'a, V> {
            KnownComponentValueListBuilder {
                value_list_builder: KnownParsedValueList::start_builder(),
            }
        }
    }

    pub(crate) struct KnownComponentValueListBuilder<'a, V: IsKnownComponentValueList<'a>> {
        value_list_builder: KnownParsedValueListBuilder<'a, V::Collection, ComponentValue<'a>>,
    }

    impl<
            'a,
            V: IsKnownComponentValueListWithConstEmpty<
                'a,
                Collection = L,
                CollectionWithConstEmpty = L,
            >,
            L: IsKnownCollectionWithConstEmpty<
                ComponentValue<'a>,
                ArrayVecType = ArrayVec<ComponentValue<'a>, ARRAY_VEC_CAP>,
                LeadVecType = LeadVec<ComponentValue<'a>, LEAD_VEC_CAP>,
            >,
            const ARRAY_VEC_CAP: usize,
            const LEAD_VEC_CAP: usize,
        > KnownComponentValueListBuilder<'a, V>
    {
        pub(crate) const fn with_push(
            self,
            value: ComponentValue<'a>,
            value_and_remaining: CopyableTokenStream<'a>,
        ) -> Self {
            if V::FILTER_OUT_WHITESPACE && value.is_whitespace() {
                return self;
            }

            Self {
                value_list_builder: self
                    .value_list_builder
                    .with_push(value, value_and_remaining),
            }
        }

        pub(crate) const fn build(
            self,
            remaining: CopyableTokenStream<'a>,
        ) -> KnownComponentValueList<'a, V> {
            KnownComponentValueList {
                value_list: self.value_list_builder.build(remaining),
            }
        }
    }
}