use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, ItemStruct, Lit, Type};

fn is_bool_type(ty: &Type) -> bool {
    if let Type::Path(type_path) = ty {
        if let Some(segment) = type_path.path.segments.last() {
            return segment.ident == "bool";
        }
    }
    false
}

#[proc_macro_attribute]
pub fn annotations(attr: TokenStream, item: TokenStream) -> TokenStream {
    let input = parse_macro_input!(item as ItemStruct);
    let name = input.ident.clone();

    // Separate fields by type
    let mut bool_fields = Vec::new();
    let mut custom_fields = Vec::new();

    for field in input.fields.iter() {
        let field_name = field.ident.clone().unwrap();
        let field_type = &field.ty;

        if is_bool_type(field_type) {
            bool_fields.push(field_name);
        } else {
            custom_fields.push((field_name, field_type));
        }
    }
    let (custom_field_names, custom_field_types): (Vec<_>, Vec<_>) =
        custom_fields.into_iter().unzip();

    // Parse comment literal
    let comm_lit = match parse_macro_input!(attr as Lit) {
        Lit::Str(lit_str) => lit_str.value(),
        _ => panic!("Expected a string literal"),
    };

    TokenStream::from(quote! {
        #[derive(Default, Debug, Copy, Clone)]
        #input

        impl #name {
            /// Autogenerated by windmill-macros
            pub fn parse(code: &str) -> Self {
                let mut res = Self::default();

                let mut lines = code.lines();

                while let Some(line) = lines.next() {
                    if line.trim().is_empty() {
                        continue;
                    }
                    if !line.starts_with(#comm_lit) {
                        break;
                    }
                    let line = line[#comm_lit.len()..].trim();
                    let (key, value) = line.split_once('=').unwrap_or((line, ""));

                    match key {
                        #(
                            stringify!(#custom_field_names) => {
                                if value.is_empty() {
                                    continue;
                                }
                                res.#custom_field_names = #custom_field_types::parse(value);
                            }
                        )*
                        #(
                            stringify!(#bool_fields) => {
                                res.#bool_fields = true;
                            }
                        )*
                        _ => {
                            // Unknown key=value annotation
                            continue;
                        }
                    }
                }
                res
            }
        }
    })
}
