//! From trait implementation generation for enum errors

use proc_macro2::TokenStream;
use quote::quote;

use crate::ir::{EnumDefinition, VariantDefinition};

/// Generate From<T> implementations for variants with #[from] fields
pub fn generate_from_impls(ir: &EnumDefinition) -> TokenStream {
    let name = &ir.name;
    let (impl_generics, ty_generics, where_clause) = ir.generics.split_for_impl();

    let from_impls: Vec<TokenStream> = ir
        .variants
        .iter()
        .filter_map(|variant| {
            match variant {
                VariantDefinition::Regular(regular) => {
                    // Find field with #[from] attribute
                    let from_field = regular.fields.iter().find(|f| f.is_from)?;
                    let variant_name = &regular.name;
                    let field_type = &from_field.ty;
                    let field_name = &from_field.rust_name;

                    Some(quote! {
                        #[automatically_derived]
                        impl #impl_generics ::std::convert::From<#field_type> for #name #ty_generics #where_clause {
                            fn from(source: #field_type) -> Self {
                                Self::#variant_name { #field_name: source }
                            }
                        }
                    })
                }
                VariantDefinition::Transparent(transparent) => {
                    if !transparent.field.is_from {
                        return None;
                    }

                    let variant_name = &transparent.name;
                    let inner_type = &transparent.field.ty;
                    Some(quote! {
                        #[automatically_derived]
                        impl #impl_generics ::std::convert::From<#inner_type> for #name #ty_generics #where_clause {
                            fn from(source: #inner_type) -> Self {
                                Self::#variant_name(source)
                            }
                        }
                    })
                }
            }
        })
        .collect();

    quote! {
        #(#from_impls)*
    }
}
