use mad_hatter::JsonInclude;

// ---------------------------------------------------------------------------
// Test 1: Array mode with #[from_file] + vars
// ---------------------------------------------------------------------------

#[derive(JsonInclude)]
#[json_include("tests/fixtures/json_include/skills.json", array, base = "tests/fixtures/json_include/")]
struct Skill {
    title: String,
    #[from_file(vars = "host, port")]
    content: String,
}

#[test]
fn test_array_with_from_file_and_vars() {
    let skills = Skill::load_all("example.com", "8080");
    assert_eq!(skills.len(), 2);

    assert_eq!(skills[0].title, "coding");
    assert!(skills[0].content.contains("example.com:8080"));
    assert!(!skills[0].content.contains("{host}"));
    assert!(!skills[0].content.contains("{port}"));

    assert_eq!(skills[1].title, "writing");
    assert!(skills[1].content.contains("example.com"));
    assert!(!skills[1].content.contains("{host}"));
}

// ---------------------------------------------------------------------------
// Test 2: Single object mode (no array, no vars)
// ---------------------------------------------------------------------------

#[derive(JsonInclude)]
#[json_include("tests/fixtures/json_include/config.json")]
struct AppConfig {
    name: String,
    version: String,
    enabled: bool,
    count: i64,
}

#[test]
fn test_single_object() {
    let config = AppConfig::load();
    assert_eq!(config.name, "test-app");
    assert_eq!(config.version, "1.0");
    assert!(config.enabled);
    assert_eq!(config.count, 42);
}

// ---------------------------------------------------------------------------
// Test 3: Array mode without #[from_file] (pure JSON values)
// ---------------------------------------------------------------------------

#[derive(JsonInclude)]
#[json_include("tests/fixtures/json_include/items.json", array)]
struct PriorityItem {
    label: String,
    priority: i64,
}

#[test]
fn test_array_without_from_file() {
    let items = PriorityItem::load_all();
    assert_eq!(items.len(), 2);
    assert_eq!(items[0].label, "alpha");
    assert_eq!(items[0].priority, 1);
    assert_eq!(items[1].label, "beta");
    assert_eq!(items[1].priority, 2);
}

// ---------------------------------------------------------------------------
// Test 4: Verify include_str! embeds file content, not path
// ---------------------------------------------------------------------------

#[test]
fn test_content_is_embedded_not_path() {
    let skills = Skill::load_all("myhost", "3000");
    // content should be the file content, not the path
    assert!(!skills[0].content.contains("coding.md"));
    assert!(skills[0].content.starts_with("This is coding"));
}

// ---------------------------------------------------------------------------
// Test 5: Bool and numeric fields work correctly
// ---------------------------------------------------------------------------

#[test]
fn test_mixed_types() {
    let config = AppConfig::load();
    let _: bool = config.enabled;
    let _: i64 = config.count;
    let _: String = config.name;
}

// ---------------------------------------------------------------------------
// Test 6: from_file without vars (pure include, no replacement)
// ---------------------------------------------------------------------------

#[derive(JsonInclude)]
#[json_include("tests/fixtures/json_include/items_with_file.json", array, base = "tests/fixtures/json_include/")]
struct PureIncludeSkill {
    title: String,
    #[from_file]
    content: String,
}

#[test]
fn test_from_file_without_vars() {
    let skills = PureIncludeSkill::load_all();
    assert_eq!(skills.len(), 1);
    assert_eq!(skills[0].title, "raw");
    // Content should have raw {host} placeholder (not replaced)
    assert!(skills[0].content.contains("{host}"));
}

// ---------------------------------------------------------------------------
// Test 7: Vars replacement works for all placeholders
// ---------------------------------------------------------------------------

#[test]
fn test_vars_replacement_complete() {
    let skills = Skill::load_all("h", "p");
    // coding.md: "This is coding skill content for {host}:{port}.\n"
    assert_eq!(skills[0].content.trim(), "This is coding skill content for h:p.");
    // writing.md: "This is writing skill content for {host}.\n"
    assert_eq!(skills[1].content.trim(), "This is writing skill content for h.");
}