use super::*;

#[test]
fn test_field_with_string_from_default() {
    let source = r#"
        pub struct Label {
            pub name: String,
        }

        impl Default for Label {
            fn default() -> Self {
                Label { name: String::from("default") }
            }
        }
    "#;

    let surface = extract_from_source(source);
    let label = &surface.types[0];
    let name_field = &label.fields[0];

    assert_eq!(
        name_field.typed_default,
        Some(crate::core::ir::DefaultValue::StringLiteral("default".to_string())),
        "String::from(...) should be extracted as StringLiteral"
    );
}

#[test]
fn test_field_with_string_new_default() {
    let source = r#"
        pub struct Buffer {
            pub data: String,
        }

        impl Default for Buffer {
            fn default() -> Self {
                Buffer { data: String::new() }
            }
        }
    "#;

    let surface = extract_from_source(source);
    let buffer = &surface.types[0];
    let data_field = &buffer.fields[0];

    assert_eq!(
        data_field.typed_default,
        Some(crate::core::ir::DefaultValue::StringLiteral(String::new())),
        "String::new() should be extracted as StringLiteral(\"\")"
    );
}

#[test]
fn test_field_with_string_to_string_default() {
    let source = r#"
        pub struct Display {
            pub content: String,
        }

        impl Default for Display {
            fn default() -> Self {
                Display { content: "placeholder".to_string() }
            }
        }
    "#;

    let surface = extract_from_source(source);
    let display = &surface.types[0];
    let content_field = &display.fields[0];

    assert_eq!(
        content_field.typed_default,
        Some(crate::core::ir::DefaultValue::StringLiteral("placeholder".to_string())),
        "\"str\".to_string() should extract the string literal"
    );
}

#[test]
fn test_field_with_char_default() {
    let source = r#"
        pub struct Separator {
            pub delimiter: char,
        }

        impl Default for Separator {
            fn default() -> Self {
                Separator { delimiter: ',' }
            }
        }
    "#;

    let surface = extract_from_source(source);
    let separator = &surface.types[0];
    let delimiter_field = &separator.fields[0];

    assert_eq!(
        delimiter_field.typed_default,
        Some(crate::core::ir::DefaultValue::StringLiteral(",".to_string())),
        "char literal should be extracted as StringLiteral"
    );
}

#[test]
fn test_field_with_vec_new_default() {
    let source = r#"
        pub struct Collection {
            pub items: Vec<String>,
        }

        impl Default for Collection {
            fn default() -> Self {
                Collection { items: Vec::new() }
            }
        }
    "#;

    let surface = extract_from_source(source);
    let collection = &surface.types[0];
    let items_field = &collection.fields[0];

    assert_eq!(
        items_field.typed_default,
        Some(crate::core::ir::DefaultValue::Empty),
        "Vec::new() should extract as Empty"
    );
}

#[test]
fn test_field_with_enum_variant_default() {
    let source = r#"
        #[derive(Clone)]
        pub enum Status {
            Pending,
            Active,
            Inactive,
        }

        pub struct Task {
            pub status: Status,
        }

        impl Default for Task {
            fn default() -> Self {
                Task { status: Status::Pending }
            }
        }
    "#;

    let surface = extract_from_source(source);
    // Filter for Task type (Status is also extracted as an enum)
    let task = surface.types.iter().find(|t| t.name == "Task").unwrap();
    let status_field = &task.fields[0];

    assert_eq!(
        status_field.typed_default,
        Some(crate::core::ir::DefaultValue::EnumVariant("Pending".to_string())),
        "SomeEnum::Variant should extract EnumVariant"
    );
}

#[test]
fn test_multiple_fields_with_different_defaults() {
    let source = r#"
        pub struct Config {
            pub name: String,
            pub count: u32,
            pub enabled: bool,
            pub threshold: f64,
        }

        impl Default for Config {
            fn default() -> Self {
                Config {
                    name: "default".into(),
                    count: 42,
                    enabled: false,
                    threshold: 0.5,
                }
            }
        }
    "#;

    let surface = extract_from_source(source);
    let config = &surface.types[0];

    assert_eq!(config.fields.len(), 4);

    // Check name field
    let name_field = &config.fields[0];
    assert_eq!(name_field.name, "name");
    assert_eq!(
        name_field.typed_default,
        Some(crate::core::ir::DefaultValue::StringLiteral("default".to_string()))
    );

    // Check count field
    let count_field = &config.fields[1];
    assert_eq!(count_field.name, "count");
    assert_eq!(
        count_field.typed_default,
        Some(crate::core::ir::DefaultValue::IntLiteral(42))
    );

    // Check enabled field
    let enabled_field = &config.fields[2];
    assert_eq!(enabled_field.name, "enabled");
    assert_eq!(
        enabled_field.typed_default,
        Some(crate::core::ir::DefaultValue::BoolLiteral(false))
    );

    // Check threshold field
    let threshold_field = &config.fields[3];
    assert_eq!(threshold_field.name, "threshold");
    assert_eq!(
        threshold_field.typed_default,
        Some(crate::core::ir::DefaultValue::FloatLiteral(0.5))
    );
}

#[test]
fn test_field_with_default_default_call() {
    let source = r#"
        pub struct Delegated {
            pub inner: u64,
        }

        impl Default for Delegated {
            fn default() -> Self {
                Delegated { inner: u64::default() }
            }
        }
    "#;

    let surface = extract_from_source(source);
    let delegated = &surface.types[0];
    let inner_field = &delegated.fields[0];

    assert_eq!(
        inner_field.typed_default,
        Some(crate::core::ir::DefaultValue::Empty),
        "T::default() should extract as Empty"
    );
}

#[test]
fn test_field_with_generic_default_call() {
    let source = r#"
        pub struct Generic {
            pub value: String,
        }

        impl Default for Generic {
            fn default() -> Self {
                Generic { value: Default::default() }
            }
        }
    "#;

    let surface = extract_from_source(source);
    let generic = &surface.types[0];
    let value_field = &generic.fields[0];

    assert_eq!(
        value_field.typed_default,
        Some(crate::core::ir::DefaultValue::Empty),
        "Default::default() should extract as Empty"
    );
}

#[test]
fn test_field_with_hashmap_new_default() {
    let source = r#"
        use std::collections::HashMap;

        pub struct Cache {
            pub data: HashMap<String, String>,
        }

        impl Default for Cache {
            fn default() -> Self {
                Cache { data: HashMap::new() }
            }
        }
    "#;

    let surface = extract_from_source(source);
    let cache = &surface.types[0];
    let data_field = &cache.fields[0];

    assert_eq!(
        data_field.typed_default,
        Some(crate::core::ir::DefaultValue::Empty),
        "HashMap::new() should extract as Empty"
    );
}

#[test]
fn test_complex_expression_defaults_to_empty() {
    let source = r#"
        pub struct Complex {
            pub result: u32,
        }

        impl Default for Complex {
            fn default() -> Self {
                Complex { result: some_function() }
            }
        }

        fn some_function() -> u32 {
            42
        }
    "#;

    let surface = extract_from_source(source);
    let complex = &surface.types[0];
    let result_field = &complex.fields[0];

    assert_eq!(
        result_field.typed_default,
        Some(crate::core::ir::DefaultValue::Empty),
        "Complex expressions like function calls should default to Empty"
    );
}

#[test]
fn test_field_with_duration_from_secs_default() {
    // Duration::from_secs(5) should extract as IntLiteral(5000) — milliseconds
    let source = r#"
        use std::time::Duration;

        pub struct Timeout {
            pub wait: Duration,
        }

        impl Default for Timeout {
            fn default() -> Self {
                Timeout { wait: Duration::from_secs(5) }
            }
        }
    "#;

    let surface = extract_from_source(source);
    let timeout = &surface.types[0];
    let wait_field = &timeout.fields[0];

    assert_eq!(
        wait_field.typed_default,
        Some(crate::core::ir::DefaultValue::IntLiteral(5000)),
        "Duration::from_secs(5) should be 5000 milliseconds"
    );
}

#[test]
fn test_field_with_duration_from_millis_default() {
    // Duration::from_millis(250) should extract as IntLiteral(250)
    let source = r#"
        use std::time::Duration;

        pub struct Backoff {
            pub delay: Duration,
        }

        impl Default for Backoff {
            fn default() -> Self {
                Backoff { delay: Duration::from_millis(250) }
            }
        }
    "#;

    let surface = extract_from_source(source);
    let backoff = &surface.types[0];
    let delay_field = &backoff.fields[0];

    assert_eq!(
        delay_field.typed_default,
        Some(crate::core::ir::DefaultValue::IntLiteral(250)),
        "Duration::from_millis(250) should be 250 milliseconds"
    );
}

#[test]
fn test_field_with_vec_macro_default() {
    // `vec![]` (empty token macro) should extract as Empty
    let source = r#"
        pub struct Pipeline {
            pub stages: Vec<String>,
        }

        impl Default for Pipeline {
            fn default() -> Self {
                Pipeline { stages: vec![] }
            }
        }
    "#;

    let surface = extract_from_source(source);
    let pipeline = &surface.types[0];
    let stages_field = &pipeline.fields[0];

    assert_eq!(
        stages_field.typed_default,
        Some(crate::core::ir::DefaultValue::Empty),
        "vec![] should extract as Empty"
    );
}

#[test]
fn test_field_with_none_default() {
    // Bare `None` should extract as DefaultValue::None
    let source = r#"
        pub struct Optional {
            pub value: Option<String>,
        }

        impl Default for Optional {
            fn default() -> Self {
                Optional { value: None }
            }
        }
    "#;

    let surface = extract_from_source(source);
    let optional_type = &surface.types[0];
    let value_field = &optional_type.fields[0];

    assert_eq!(
        value_field.typed_default,
        Some(crate::core::ir::DefaultValue::None),
        "Bare None should extract as DefaultValue::None"
    );
}

#[test]
fn test_unary_negation_on_non_numeric_falls_back_to_empty() {
    // Negating something that isn't an int or float literal — should return Empty.
    // We exercise this indirectly by using a call expression that itself returns Empty.
    let source = r#"
        pub struct Unusual {
            pub val: i32,
        }

        fn compute() -> i32 { 0 }

        impl Default for Unusual {
            fn default() -> Self {
                // This will be parsed as Unary(Neg, Call(...)) — the inner call returns Empty,
                // so the negation should also return Empty.
                Unusual { val: -(compute()) }
            }
        }
    "#;

    let surface = extract_from_source(source);
    let unusual = &surface.types[0];
    let val_field = &unusual.fields[0];

    assert_eq!(
        val_field.typed_default,
        Some(crate::core::ir::DefaultValue::Empty),
        "Negating a non-literal expression should fall back to Empty"
    );
}
