extern crate proc_macro2;
extern crate quote;
extern crate syn;

use syn::{Attribute, Expr, Ident, MetaNameValue, Path};

/// `#[primitive(PrimitiveName)]` in enums
pub fn get_primitive_name(attrs: &[Attribute]) -> Option<Ident> {
    attrs.iter().find_map(|attr| {
        if !attr.path().is_ident("primitive") {
            return None;
        }

        attr.parse_args().unwrap()
    })
}

/// `#[rapira(static_size = None)]` in enums
pub fn enum_static_size(attrs: &[Attribute]) -> Option<Expr> {
    attrs.iter().find_map(|attr| {
        if !attr.path().is_ident("rapira") {
            return None;
        }

        if let Ok(nv) = attr.parse_args::<MetaNameValue>() {
            return nv.path.is_ident("static_size").then_some(nv.value);
        }

        None
    })
}

/// `#[rapira(min_size = 0)]`
pub fn min_size(attrs: &[Attribute]) -> Option<Expr> {
    attrs.iter().find_map(|attr| {
        if !attr.path().is_ident("rapira") {
            return None;
        }

        if let Ok(nv) = attr.parse_args::<MetaNameValue>() {
            return nv.path.is_ident("min_size").then_some(nv.value);
        }

        None
    })
}

/// `#[rapira(version = 2)]` on struct
pub fn version_attr(attrs: &[Attribute]) -> Option<u8> {
    attrs.iter().find_map(|attr| {
        if !attr.path().is_ident("rapira") {
            return None;
        }

        if let Ok(nv) = attr.parse_args::<MetaNameValue>()
            && nv.path.is_ident("version")
        {
            if let Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Int(i),
                ..
            }) = &nv.value
            {
                return Some(i.base10_parse::<u8>().expect("version value must be u8"));
            }
            panic!("version value must be an integer literal");
        }

        None
    })
}

/// `#[rapira(peer)]` — emit `from_slice_with_peer_ctx` override (requires `GetType` on the type).
pub fn peer_attr(attrs: &[Attribute]) -> bool {
    for item in attrs.iter() {
        if item.path().is_ident("rapira")
            && let Ok(nv) = item.parse_args::<Path>()
            && nv.is_ident("peer")
        {
            return true;
        }
    }
    false
}

/// `#[rapira(debug)]`
pub fn debug_attr(attrs: &[Attribute]) -> bool {
    for item in attrs.iter() {
        if item.path().is_ident("rapira")
            && let Ok(nv) = item.parse_args::<Path>()
            && nv.is_ident("debug")
        {
            return true;
        }
    }
    false
}
