use mad_hatter::Promptable;
use mad_hatter::llm::Promptable as _;

// Test struct-level include
#[derive(Promptable)]
#[prompt(include = "fixtures/test_prompt.md")]
struct CaptureRequest {
    #[prompt("Current knowledge base")]
    pub current_knowledge: String,
    #[prompt("Action logs")]
    pub action_logs: String,
}

#[test]
fn test_struct_level_include() {
    let req = CaptureRequest {
        current_knowledge: "Alice is an AI agent".to_string(),
        action_logs: "Sent a message\nRead a file".to_string(),
    };
    let output = req.to_markdown();

    // struct-level include should appear as raw text (no // prefix)
    assert!(output.contains("You are a knowledge extraction agent."), "should contain first line");
    assert!(output.contains("Your task is to analyze conversations and extract structured knowledge."), "should contain second line");
    assert!(output.contains("- Focus on factual information"), "should contain rule line");
    assert!(output.contains("- Output in structured format"), "should contain last rule");
    // should NOT have // prefix
    assert!(!output.contains("// You are a knowledge extraction agent."), "should not have // prefix");

    // fields should still render normally
    assert!(output.contains("Current knowledge base"), "should contain field title");
    assert!(output.contains("Alice is an AI agent"), "should contain field value");
    assert!(output.contains("Action logs"), "should contain second field title");
}

// Test field-level include
#[derive(Promptable)]
struct FieldIncludeTest {
    #[prompt(include = "fixtures/field_prompt.md")]
    pub logs: String,
    #[prompt("Normal field")]
    pub normal: String,
}

#[test]
fn test_field_level_include() {
    let req = FieldIncludeTest {
        logs: "Log entry 1\nLog entry 2".to_string(),
        normal: "hello".to_string(),
    };
    let output = req.to_markdown();

    // field with include should use file content as title
    assert!(output.contains("Recent activity logs from the agent"), "should contain included field title");
    // normal field should work as before
    assert!(output.contains("Normal field"), "should contain normal field title");
    assert!(output.contains("hello"), "should contain normal field value");
}

// Test struct-level mixed (literal + include)
#[derive(Promptable)]
#[prompt("System preamble line")]
#[prompt(include = "fixtures/test_prompt.md")]
struct MixedPreambleTest {
    #[prompt("Data")]
    pub data: String,
}

#[test]
fn test_mixed_preamble() {
    let req = MixedPreambleTest {
        data: "test data".to_string(),
    };
    let output = req.to_markdown();

    // literal preamble should appear (raw, no // prefix)
    assert!(output.contains("System preamble line"), "should contain literal preamble");
    assert!(!output.contains("// System preamble line"), "should not have // prefix on literal");
    // include preamble should also appear (raw, no // prefix)
    assert!(output.contains("You are a knowledge extraction agent."), "should contain included preamble");
    // field should render
    assert!(output.contains("Data"), "should contain field title");
    assert!(output.contains("test data"), "should contain field value");
}

// Test that literal-only prompt still works (regression)
#[derive(Promptable)]
#[prompt("This is a literal-only preamble")]
struct LiteralOnlyTest {
    #[prompt("Field A")]
    pub field_a: String,
}

#[test]
fn test_literal_only_unchanged() {
    let req = LiteralOnlyTest {
        field_a: "value".to_string(),
    };
    let output = req.to_markdown();
    assert!(output.contains("This is a literal-only preamble"), "literal preamble should work");
    assert!(!output.contains("// This is a literal-only preamble"), "should not have // prefix");
    assert!(output.contains("Field A"), "field title should work");
    assert!(output.contains("value"), "field value should work");
}

// Test include with no other prompt attrs on struct
#[derive(Promptable)]
#[prompt(include = "fixtures/test_prompt.md")]
struct IncludeOnlyTest {
    #[prompt("Item")]
    pub item: String,
}

#[test]
fn test_include_only() {
    let req = IncludeOnlyTest {
        item: "something".to_string(),
    };
    let output = req.to_markdown();
    assert!(output.contains("You are a knowledge extraction agent."), "include should work alone");
    assert!(output.contains("- Output in structured format"), "should contain all lines");
    assert!(output.contains("something"), "field should render");
}

// Test empty lines in included file are preserved as empty comments
#[test]
fn test_include_preserves_empty_lines() {
    let req = CaptureRequest {
        current_knowledge: "k".to_string(),
        action_logs: "a".to_string(),
    };
    let output = req.to_markdown();
    // The test_prompt.md has an empty line between paragraphs
    // Empty lines should be preserved as empty lines
    assert!(output.contains("\n\n"), "empty lines should be preserved");
}