use darling::FromDeriveInput;
use syn::parse_quote;

mod foo {
    pub mod bar {
        pub fn init() -> String {
            String::from("hello")
        }
    }
}

#[derive(FromDeriveInput)]
#[darling(attributes(speak))]
pub struct SpeakerOpts {
    #[darling(default = "foo::bar::init")]
    first_word: String,
}

#[test]
fn path_default() {
    let speaker: SpeakerOpts = FromDeriveInput::from_derive_input(&parse_quote! {
        struct Foo;
    })
    .expect("Unit struct with no attrs should parse");

    assert_eq!(speaker.first_word, "hello");
}

/// Tests in this module capture the somewhat-confusing behavior observed when defaults
/// are set at both the field and container level.
///
/// The general rule is that more-specific declarations preempt less-specific ones; this is
/// unsurprising and allows for granular control over what happens when parsing an AST.
mod stacked_defaults {
    use darling::{FromDeriveInput, FromMeta};
    use syn::parse_quote;

    fn jane() -> String {
        "Jane".into()
    }

    #[derive(FromMeta)]
    #[darling(default)]
    struct PersonName {
        #[darling(default = "jane")]
        first: String,
        #[darling(default)]
        middle: String,
        last: String,
    }

    impl Default for PersonName {
        fn default() -> Self {
            Self {
                first: "John".into(),
                middle: "T".into(),
                last: "Doe".into(),
            }
        }
    }

    #[derive(FromDeriveInput)]
    #[darling(attributes(person))]
    struct Person {
        #[darling(default)]
        name: PersonName,
        age: u8,
    }

    #[test]
    fn name_first_only() {
        let person = Person::from_derive_input(&parse_quote! {
            #[person(name(first = "Bill"), age = 5)]
            struct Foo;
        })
        .unwrap();

        assert_eq!(person.name.first, "Bill");
        assert_eq!(
            person.name.middle, "",
            "Explicit field-level default should preempt container-level default"
        );
        assert_eq!(
            person.name.last, "Doe",
            "Absence of a field-level default falls back to container-level default"
        );
    }

    /// This is the most surprising case. The presence of `name()` means we invoke
    /// `PersonName::from_list(&[])`. When that finishes parsing each of the zero nested
    /// items it has received, it will then start filling in missing fields, using the
    /// explicit field-level defaults for `first` and `middle`, while for `last` it will
    /// use the `last` field from the container-level default.
    #[test]
    fn name_empty_list() {
        let person = Person::from_derive_input(&parse_quote! {
            #[person(name(), age = 5)]
            struct Foo;
        })
        .unwrap();

        assert_eq!(person.name.first, "Jane");
        assert_eq!(person.name.middle, "");
        assert_eq!(person.name.last, "Doe");
    }

    #[test]
    fn no_name() {
        let person = Person::from_derive_input(&parse_quote! {
            #[person(age = 5)]
            struct Foo;
        })
        .unwrap();

        assert_eq!(person.age, 5);
        assert_eq!(
            person.name.first, "John",
            "If `name` is not specified, `Person`'s field-level default should be used"
        );
        assert_eq!(person.name.middle, "T");
        assert_eq!(person.name.last, "Doe");
    }
}

mod implicit_default {
    use darling::{util::Flag, FromDeriveInput};
    use syn::parse_quote;

    // No use of `darling(default)` here at all!
    // This struct will fill in missing fields using FromMeta::from_none.
    #[derive(FromDeriveInput)]
    #[darling(attributes(person))]
    struct Person {
        first_name: String,
        last_name: Option<String>,
        lefty: Flag,
    }

    #[test]
    fn missing_fields_fill() {
        let person = Person::from_derive_input(&parse_quote! {
            #[person(first_name = "James")]
            struct Foo;
        })
        .unwrap();

        assert_eq!(person.first_name, "James");
        assert_eq!(person.last_name, None);
        assert!(!person.lefty.is_present());
    }
}

/// Test that a field-level implicit default using FromMeta::from_none is superseded
/// by the parent declaring `#[darling(default)]`.
mod overridden_implicit_default {
    use darling::{util::Flag, FromDeriveInput};
    use syn::parse_quote;

    #[derive(FromDeriveInput)]
    #[darling(default, attributes(person))]
    struct Person {
        first_name: String,
        last_name: Option<String>,
        lefty: Flag,
    }

    impl Default for Person {
        fn default() -> Self {
            Self {
                first_name: "Jane".into(),
                last_name: Some("Doe".into()),
                lefty: Flag::default(),
            }
        }
    }

    #[test]
    fn fill_missing() {
        let person = Person::from_derive_input(&parse_quote!(
            #[person(last_name = "Archer")]
            struct Foo;
        ))
        .unwrap();

        assert_eq!(person.first_name, "Jane");
        assert_eq!(person.last_name, Some("Archer".into()));
        assert!(!person.lefty.is_present());
    }
}
