use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use syn::{braced, punctuated::Punctuated, Token};

use super::{
    common::{Attributes, TypeRepr},
    document::DocumentItemAttributes,
};

#[derive(Clone)]
pub struct EnumTypeVariant {
    pub attributes: Attributes,
    pub discriminant: syn::Ident,
    pub value: syn::LitInt,
}

#[derive(Clone)]
pub struct EnumType {
    pub attributes: Attributes,
    pub name: syn::Ident,
    pub repr: TypeRepr,
    pub variants: Punctuated<EnumTypeVariant, Token![,]>,
}

impl syn::parse::Parse for EnumTypeVariant {
    fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
        let attributes = input.parse()?;
        let discriminant = input.parse()?;
        input.parse::<Token![=]>()?;
        let value = input.parse()?;
        // let value = if input.peek(Token![=]) {
        //     input.parse::<Token![=]>()?;
        //     let value = input.parse()?;
        //     Some(value)
        // } else {
        //     None
        // };
        Ok(Self {
            attributes,
            discriminant,
            value,
        })
    }
}

impl syn::parse::Parse for EnumType {
    fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
        let variants;
        let attributes = input.parse()?;
        let name = input.parse()?;
        let repr = input.parse()?;
        braced!(variants in input);
        let variants = variants.parse_terminated(EnumTypeVariant::parse, Token![,])?;
        Ok(Self {
            attributes,
            name,
            repr,
            variants,
        })
    }
}

impl DocumentItemAttributes for EnumType {
    fn extend_attributes<I: IntoIterator<Item = syn::Attribute>>(&mut self, attrs: I) {
        self.attributes.extend(attrs);
    }
}

impl ToTokens for EnumTypeVariant {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Self {
            attributes,
            discriminant,
            value,
        } = self;
        // let value = value.as_ref().map(|val| quote!(= #val));
        tokens.extend(quote! {
            #attributes
            #discriminant = #value
        })
    }
}

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