use std::ops::{Deref, DerefMut};

use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use syn::{parenthesized, Token};

#[derive(Clone)]
pub struct TypeRepr(pub syn::Ident);
#[derive(Clone)]
pub struct Attributes(pub Vec<syn::Attribute>);

impl Attributes {
    pub fn new() -> Self {
        Self(vec![])
    }

    pub fn filtered<P: Fn(&syn::Attribute) -> bool>(&self, pred: P) -> Self {
        Self(self.0.iter().cloned().filter(pred).collect())
    }
}

impl Deref for Attributes {
    type Target = Vec<syn::Attribute>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for Attributes {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl syn::parse::Parse for Attributes {
    fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
        syn::Attribute::parse_outer(input).map(Self)
    }
}

impl syn::parse::Parse for TypeRepr {
    fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
        let content;
        parenthesized!(content in input);
        let content = content.parse_terminated(syn::Ident::parse, Token![,])?;
        let mut content = content.into_iter();
        let ty = content.next().expect("TODO insert error here");
        if content.len() != 0 {
            todo!("TODO insert error here");
        }
        Ok(Self(ty))
    }
}

impl ToTokens for TypeRepr {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Self(repr) = self;
        tokens.extend(quote!((#repr)))
    }
}

impl ToTokens for Attributes {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Self(attrs) = self;
        for attr in attrs {
            attr.to_tokens(tokens);
        }
    }
}
