use super::{DefaultValue, GetterField};
use crate::DefaultValue::Value;
use proc_macro2::{Ident, Span, TokenStream as TokenStream2};
use proc_macro_error2::abort_call_site;
use quote::quote;
use syn::{self, ext::IdentExt};


pub fn implement(field: &GetterField) -> TokenStream2 {
    let field_name = field
        .ident
        .clone()
        .unwrap_or_else(|| abort_call_site!("没有字段名字"));

    let fn_name = if field_name.to_string().starts_with("r#") {
        field_name.clone()
    } else {
        Ident::new(&format!("{}", field_name.unraw()), Span::call_site())
    };
    let field_ty = &field.ty;
    let inner_type = &field.inner_type;

    let ty = match inner_type {
        Some(inner_type) => inner_type,
        None => &field_ty,
    };

    let primitive = field.is_primitive;
    let string = field.is_string;
    let return_ty = if primitive {
        quote! {#ty}
    } else if string {
        quote! {&str}
    } else {
        quote! {&#ty}
    };

    let content = if field.is_option {
        let default_value = &field.default;
        let default_value = default_value.as_ref().unwrap_or(&DefaultValue::NoValue);
        match default_value {
            Value(default) => {
                if primitive {
                    quote! {
                        self.#field_name.unwrap_or(#default)
                    }
                } else if string {
                    quote! {
                        &self.#field_name.as_deref().unwrap_or(#default)
                    }
                } else {
                    quote! {
                        &self.#field_name.unwrap_or(&#default)
                    }
                }
            }
            _ => {
                if primitive {
                    quote! {
                        self.#field_name.unwrap_or_default()
                    }
                } else if string {
                    quote! {
                        &self.#field_name.as_deref().unwrap_or("")
                    }
                } else {
                    quote! {
                        &self.#field_name.unwrap_or_default()
                    }
                }
            }
        }
    } else {
        if primitive {
            quote! {
                self.#field_name
            }
        } else {
            quote! {
                &self.#field_name
            }
        }
    };

    let public = field.public;
    let visibility = if public {
        quote! {
            pub
        }
    } else {
        quote! {}
    };
    quote! {
        #[inline(always)]
        #visibility fn #fn_name(&self) -> #return_ty {
            #content
        }
    }
}