//! Integration tests for the full conversion pipeline

use crate::{
    resolve::convert::convert_file,
    syntax::{
        ast::*,
        FileParser,
    },
    types::*,
};

/// Helper to parse and convert a source string
fn parse_and_convert(source: &str) -> Result<Vec<ResolvedDeclaration>, Box<dyn std::error::Error>> {
    let lexer = crate::syntax::lexer::Lexer::new(source);
    let file = FileParser::new().parse(lexer)?;
    Ok(convert_file(&file)?)
}

#[test]
fn test_simple_character_end_to_end() {
    let source = r#"
        character Martha {
            age: 34
            health: 0.8
        }
    "#;

    let resolved = parse_and_convert(source).unwrap();
    assert_eq!(resolved.len(), 1);

    match &resolved[0] {
        | ResolvedDeclaration::Character(c) => {
            assert_eq!(c.name, "Martha");
            assert_eq!(c.fields.len(), 2);
            assert_eq!(c.fields.get("age"), Some(&Value::Number(34)));
            assert_eq!(c.fields.get("health"), Some(&Value::Decimal(0.8)));
        },
        | _ => panic!("Expected Character"),
    }
}

#[test]
fn test_character_with_prose_end_to_end() {
    let source = r#"
        character Martha {
            age: 34
            backstory: ---backstory
Martha grew up in a small town.
She loved baking from a young age.
---
        }
    "#;

    let resolved = parse_and_convert(source).unwrap();
    assert_eq!(resolved.len(), 1);

    match &resolved[0] {
        | ResolvedDeclaration::Character(c) => {
            assert_eq!(c.name, "Martha");
            assert_eq!(c.fields.len(), 1);
            assert_eq!(c.fields.get("age"), Some(&Value::Number(34)));
            assert_eq!(c.prose_blocks.len(), 1);

            let backstory = c.prose_blocks.get("backstory").unwrap();
            assert_eq!(backstory.tag, "backstory");
            assert!(backstory.content.contains("Martha grew up"));
        },
        | _ => panic!("Expected Character"),
    }
}

#[test]
fn test_multiple_declarations_end_to_end() {
    let source = r#"
        character Martha {
            age: 34
        }

        character David {
            age: 36
        }
    "#;

    let resolved = parse_and_convert(source).unwrap();
    assert_eq!(resolved.len(), 2);

    let char_count = resolved
        .iter()
        .filter(|d| matches!(d, ResolvedDeclaration::Character(_)))
        .count();
    assert_eq!(char_count, 2);
}

#[test]
fn test_relationship_end_to_end() {
    let source = r#"
        relationship Spousal {
            Martha { }
            David { }
            bond: 0.9
        }
    "#;

    let resolved = parse_and_convert(source).unwrap();
    assert_eq!(resolved.len(), 1);

    match &resolved[0] {
        | ResolvedDeclaration::Relationship(r) => {
            assert_eq!(r.name, "Spousal");
            assert_eq!(r.participants.len(), 2);
            assert_eq!(r.fields.get("bond"), Some(&Value::Decimal(0.9)));
        },
        | _ => panic!("Expected Relationship"),
    }
}

#[test]
fn test_life_arc_end_to_end() {
    let source = r#"
        life_arc Growth {
            state child {
                on age > 12 -> teen
            }
            state teen {
                on age > 18 -> adult
            }
            state adult {}
        }
    "#;

    let resolved = parse_and_convert(source).unwrap();
    assert_eq!(resolved.len(), 1);

    match &resolved[0] {
        | ResolvedDeclaration::LifeArc(la) => {
            assert_eq!(la.name, "Growth");
            assert_eq!(la.states.len(), 3);
            assert_eq!(la.states[0].name, "child");
            assert_eq!(la.states[1].name, "teen");
            assert_eq!(la.states[2].name, "adult");
        },
        | _ => panic!("Expected LifeArc"),
    }
}

#[test]
fn test_behavior_tree_end_to_end() {
    let source = r#"
        behavior WorkAtBakery {
            then {
                walk
                work(duration: 8h)
                rest
            }
        }
    "#;

    let resolved = parse_and_convert(source).unwrap();
    assert_eq!(resolved.len(), 1);

    match &resolved[0] {
        | ResolvedDeclaration::Behavior(b) => {
            assert_eq!(b.name, "WorkAtBakery");
            // Root should be a Sequence node
            assert!(matches!(b.root, BehaviorNode::Sequence { .. }));
        },
        | _ => panic!("Expected Behavior"),
    }
}

#[test]
fn test_schedule_end_to_end() {
    let source = r#"
        schedule DailyRoutine {
            08:00 -> 12:00: work { }
            12:00 -> 13:00: lunch { }
            13:00 -> 17:00: work { }
        }
    "#;

    let resolved = parse_and_convert(source).unwrap();
    assert_eq!(resolved.len(), 1);

    match &resolved[0] {
        | ResolvedDeclaration::Schedule(s) => {
            assert_eq!(s.name, "DailyRoutine");
            assert_eq!(s.blocks.len(), 3);
            assert_eq!(s.blocks[0].activity, "work");
            assert_eq!(s.blocks[1].activity, "lunch");
            assert_eq!(s.blocks[2].activity, "work");
        },
        | _ => panic!("Expected Schedule"),
    }
}

#[test]
fn test_institution_end_to_end() {
    let source = r#"
        institution Bakery {
            employees: 5
            revenue: 50000
        }
    "#;

    let resolved = parse_and_convert(source).unwrap();
    assert_eq!(resolved.len(), 1);

    match &resolved[0] {
        | ResolvedDeclaration::Institution(i) => {
            assert_eq!(i.name, "Bakery");
            assert_eq!(i.fields.get("employees"), Some(&Value::Number(5)));
            assert_eq!(i.fields.get("revenue"), Some(&Value::Number(50000)));
        },
        | _ => panic!("Expected Institution"),
    }
}

#[test]
fn test_location_end_to_end() {
    let source = r#"
        location Bakery {
            x: 100
            y: 200
        }
    "#;

    let resolved = parse_and_convert(source).unwrap();
    assert_eq!(resolved.len(), 1);

    match &resolved[0] {
        | ResolvedDeclaration::Location(l) => {
            assert_eq!(l.name, "Bakery");
            assert_eq!(l.fields.get("x"), Some(&Value::Number(100)));
            assert_eq!(l.fields.get("y"), Some(&Value::Number(200)));
        },
        | _ => panic!("Expected Location"),
    }
}

#[test]
fn test_species_end_to_end() {
    let source = r#"
        species Human {
            lifespan: 80
            intelligence: 0.9
        }
    "#;

    let resolved = parse_and_convert(source).unwrap();
    assert_eq!(resolved.len(), 1);

    match &resolved[0] {
        | ResolvedDeclaration::Species(s) => {
            assert_eq!(s.name, "Human");
            assert_eq!(s.fields.get("lifespan"), Some(&Value::Number(80)));
            assert_eq!(s.fields.get("intelligence"), Some(&Value::Decimal(0.9)));
        },
        | _ => panic!("Expected Species"),
    }
}

#[test]
fn test_template_end_to_end() {
    let source = r#"
        template Adult {
            age: 20..60
            health: 0.5..1.0
        }
    "#;

    let resolved = parse_and_convert(source).unwrap();
    assert_eq!(resolved.len(), 1);

    match &resolved[0] {
        | ResolvedDeclaration::Template(t) => {
            assert_eq!(t.name, "Adult");
            assert_eq!(t.fields.len(), 2);
            // Templates keep their range values
            assert!(matches!(t.fields.get("age"), Some(Value::Range(_, _))));
        },
        | _ => panic!("Expected Template"),
    }
}

#[test]
fn test_use_declarations_are_skipped() {
    let source = r#"
        use characters::*;

        character Martha {
            age: 34
        }
    "#;

    let resolved = parse_and_convert(source).unwrap();
    // Should only have character, not use declaration
    assert_eq!(resolved.len(), 1);
    assert!(matches!(resolved[0], ResolvedDeclaration::Character(_)));
}

#[test]
fn test_complex_mixed_file() {
    let source = r#"
        use relationships::*;

        character Martha {
            age: 34
            backstory: ---backstory
Martha grew up in a small town.
---
        }

        character David {
            age: 36
        }

        relationship Spousal {
            Martha { }
            David { }
            bond: 0.9
        }

        schedule DailyRoutine {
            08:00 -> 12:00: work { }
            12:00 -> 13:00: lunch { }
        }
    "#;

    let resolved = parse_and_convert(source).unwrap();

    // Count each type
    let chars = resolved
        .iter()
        .filter(|d| matches!(d, ResolvedDeclaration::Character(_)))
        .count();
    let rels = resolved
        .iter()
        .filter(|d| matches!(d, ResolvedDeclaration::Relationship(_)))
        .count();
    let scheds = resolved
        .iter()
        .filter(|d| matches!(d, ResolvedDeclaration::Schedule(_)))
        .count();

    assert_eq!(chars, 2);
    assert_eq!(rels, 1);
    assert_eq!(scheds, 1);
    assert_eq!(resolved.len(), 4); // Total, excluding use declaration
}

#[test]
fn test_duplicate_field_names_error() {
    let source = r#"
        character Martha {
            age: 34
            age: 35
        }
    "#;

    let result = parse_and_convert(source);
    assert!(result.is_err(), "Duplicate field names should cause error");
}

#[test]
fn test_all_value_types_convert() {
    let source = r#"
        character Test {
            int_val: 42
            float_val: 3.5
            bool_val: true
            string_val: "hello"
        }
    "#;

    let resolved = parse_and_convert(source).unwrap();
    match &resolved[0] {
        | ResolvedDeclaration::Character(c) => {
            assert_eq!(c.fields.get("int_val"), Some(&Value::Number(42)));
            assert_eq!(c.fields.get("float_val"), Some(&Value::Decimal(3.5)));
            assert_eq!(c.fields.get("bool_val"), Some(&Value::Boolean(true)));
            assert_eq!(
                c.fields.get("string_val"),
                Some(&Value::Text("hello".to_string()))
            );
        },
        | _ => panic!("Expected Character"),
    }
}
