//! Tests for resource linking syntax (uses behaviors/schedules)

use crate::syntax::{
    ast::*,
    lexer::Lexer,
    FileParser,
};

#[test]
fn test_character_with_single_behavior_link() {
    let input = r#"
character Martha: Human {
    age: 42
    uses behaviors: [
        { tree: BakeryWork, priority: normal }
    ]
}
"#;

    let lexer = Lexer::new(input);
    let parser = FileParser::new();
    let result = parser.parse(lexer);

    assert!(result.is_ok(), "Failed to parse: {:?}", result.err());

    let file = result.unwrap();
    assert_eq!(file.declarations.len(), 1);

    match &file.declarations[0] {
        | Declaration::Character(c) => {
            assert_eq!(c.name, "Martha");
            assert_eq!(c.species.as_ref().unwrap(), "Human");

            // Check behavior links
            assert!(c.uses_behaviors.is_some());
            let behaviors = c.uses_behaviors.as_ref().unwrap();
            assert_eq!(behaviors.len(), 1);
            assert_eq!(behaviors[0].tree, vec!["BakeryWork"]);
            assert_eq!(behaviors[0].priority, Priority::Normal);
            assert!(behaviors[0].condition.is_none());
        },
        | _ => panic!("Expected Character declaration"),
    }
}

#[test]
fn test_character_with_multiple_behavior_links() {
    let input = r#"
character Martha: Human {
    uses behaviors: [
        { tree: HandleUrgentNeeds, priority: critical },
        { tree: BakeryWork, priority: normal, when: time.hour >= 5 and time.hour < 13 },
        { tree: Idle, priority: low }
    ]
}
"#;

    let lexer = Lexer::new(input);
    let parser = FileParser::new();
    let result = parser.parse(lexer);

    assert!(result.is_ok(), "Failed to parse: {:?}", result.err());

    let file = result.unwrap();
    match &file.declarations[0] {
        | Declaration::Character(c) => {
            let behaviors = c.uses_behaviors.as_ref().unwrap();
            assert_eq!(behaviors.len(), 3);

            assert_eq!(behaviors[0].tree, vec!["HandleUrgentNeeds"]);
            assert_eq!(behaviors[0].priority, Priority::Critical);

            assert_eq!(behaviors[1].tree, vec!["BakeryWork"]);
            assert_eq!(behaviors[1].priority, Priority::Normal);
            assert!(behaviors[1].condition.is_some()); // Has when clause

            assert_eq!(behaviors[2].tree, vec!["Idle"]);
            assert_eq!(behaviors[2].priority, Priority::Low);
        },
        | _ => panic!("Expected Character declaration"),
    }
}

#[test]
fn test_character_with_schedule_link() {
    let input = r#"
character Martha: Human {
    uses schedule: BakerSchedule
}
"#;

    let lexer = Lexer::new(input);
    let parser = FileParser::new();
    let result = parser.parse(lexer);

    assert!(result.is_ok(), "Failed to parse: {:?}", result.err());

    let file = result.unwrap();
    match &file.declarations[0] {
        | Declaration::Character(c) => {
            assert!(c.uses_schedule.is_some());
            let schedules = c.uses_schedule.as_ref().unwrap();
            assert_eq!(schedules.len(), 1);
            assert_eq!(schedules[0], "BakerSchedule");
        },
        | _ => panic!("Expected Character declaration"),
    }
}

#[test]
fn test_character_with_multiple_schedules() {
    let input = r#"
character Martha: Human {
    uses schedules: [WorkdaySchedule, WeekendSchedule]
}
"#;

    let lexer = Lexer::new(input);
    let parser = FileParser::new();
    let result = parser.parse(lexer);

    assert!(result.is_ok(), "Failed to parse: {:?}", result.err());

    let file = result.unwrap();
    match &file.declarations[0] {
        | Declaration::Character(c) => {
            let schedules = c.uses_schedule.as_ref().unwrap();
            assert_eq!(schedules.len(), 2);
            assert_eq!(schedules[0], "WorkdaySchedule");
            assert_eq!(schedules[1], "WeekendSchedule");
        },
        | _ => panic!("Expected Character declaration"),
    }
}

#[test]
fn test_character_with_behaviors_and_schedule() {
    let input = r#"
character Martha: Human {
    age: 42
    uses behaviors: [
        { tree: BakeryWork, priority: normal }
    ]
    profession: "Baker"
    uses schedule: BakerSchedule
}
"#;

    let lexer = Lexer::new(input);
    let parser = FileParser::new();
    let result = parser.parse(lexer);

    assert!(result.is_ok(), "Failed to parse: {:?}", result.err());

    let file = result.unwrap();
    match &file.declarations[0] {
        | Declaration::Character(c) => {
            // Check fields
            assert_eq!(c.fields.len(), 2);

            // Check behaviors
            assert!(c.uses_behaviors.is_some());
            let behaviors = c.uses_behaviors.as_ref().unwrap();
            assert_eq!(behaviors.len(), 1);

            // Check schedule
            assert!(c.uses_schedule.is_some());
            let schedules = c.uses_schedule.as_ref().unwrap();
            assert_eq!(schedules.len(), 1);
        },
        | _ => panic!("Expected Character declaration"),
    }
}

#[test]
fn test_institution_with_behavior_links() {
    let input = r#"
institution Bakery {
    type: "Business"
    uses behaviors: [
        { tree: BakeryOperations, priority: high }
    ]
}
"#;

    let lexer = Lexer::new(input);
    let parser = FileParser::new();
    let result = parser.parse(lexer);

    assert!(result.is_ok(), "Failed to parse: {:?}", result.err());

    let file = result.unwrap();
    match &file.declarations[0] {
        | Declaration::Institution(inst) => {
            assert_eq!(inst.name, "Bakery");
            assert!(inst.uses_behaviors.is_some());
            let behaviors = inst.uses_behaviors.as_ref().unwrap();
            assert_eq!(behaviors.len(), 1);
            assert_eq!(behaviors[0].tree, vec!["BakeryOperations"]);
            assert_eq!(behaviors[0].priority, Priority::High);
        },
        | _ => panic!("Expected Institution declaration"),
    }
}

#[test]
fn test_qualified_path_behavior_tree() {
    let input = r#"
character Martha: Human {
    uses behaviors: [
        { tree: village::baker::BakeryWork, priority: normal }
    ]
}
"#;

    let lexer = Lexer::new(input);
    let parser = FileParser::new();
    let result = parser.parse(lexer);

    assert!(result.is_ok(), "Failed to parse: {:?}", result.err());

    let file = result.unwrap();
    match &file.declarations[0] {
        | Declaration::Character(c) => {
            let behaviors = c.uses_behaviors.as_ref().unwrap();
            assert_eq!(behaviors[0].tree, vec!["village", "baker", "BakeryWork"]);
        },
        | _ => panic!("Expected Character declaration"),
    }
}

#[test]
fn test_all_priority_levels() {
    let input = r#"
character Test: Human {
    uses behaviors: [
        { tree: A, priority: low },
        { tree: B, priority: normal },
        { tree: C, priority: high },
        { tree: D, priority: critical }
    ]
}
"#;

    let lexer = Lexer::new(input);
    let parser = FileParser::new();
    let result = parser.parse(lexer);

    assert!(result.is_ok(), "Failed to parse: {:?}", result.err());

    let file = result.unwrap();
    match &file.declarations[0] {
        | Declaration::Character(c) => {
            let behaviors = c.uses_behaviors.as_ref().unwrap();
            assert_eq!(behaviors[0].priority, Priority::Low);
            assert_eq!(behaviors[1].priority, Priority::Normal);
            assert_eq!(behaviors[2].priority, Priority::High);
            assert_eq!(behaviors[3].priority, Priority::Critical);
        },
        | _ => panic!("Expected Character declaration"),
    }
}

#[test]
fn test_template_with_simple_behavior_links() {
    let input = r#"
template Baker {
    uses behaviors: BakingSkills, CustomerService
    specialty: "bread"
    baking_skill: 0.0..1.0
}
"#;

    let lexer = Lexer::new(input);
    let parser = FileParser::new();
    let result = parser.parse(lexer);

    assert!(result.is_ok(), "Failed to parse: {:?}", result.err());

    let file = result.unwrap();
    match &file.declarations[0] {
        | Declaration::Template(t) => {
            assert_eq!(t.name, "Baker");

            // Check behavior links
            assert!(t.uses_behaviors.is_some());
            let behaviors = t.uses_behaviors.as_ref().unwrap();
            assert_eq!(behaviors.len(), 2);
            assert_eq!(behaviors[0].tree, vec!["BakingSkills"]);
            assert_eq!(behaviors[0].priority, Priority::Normal);
            assert_eq!(behaviors[1].tree, vec!["CustomerService"]);
            assert_eq!(behaviors[1].priority, Priority::Normal);
        },
        | _ => panic!("Expected Template declaration"),
    }
}

#[test]
fn test_template_with_schedule_link() {
    let input = r#"
template Baker {
    uses schedule: BakerSchedule
    specialty: "bread"
}
"#;

    let lexer = Lexer::new(input);
    let parser = FileParser::new();
    let result = parser.parse(lexer);

    assert!(result.is_ok(), "Failed to parse: {:?}", result.err());

    let file = result.unwrap();
    match &file.declarations[0] {
        | Declaration::Template(t) => {
            assert_eq!(t.name, "Baker");

            // Check schedule link
            assert!(t.uses_schedule.is_some());
            let schedules = t.uses_schedule.as_ref().unwrap();
            assert_eq!(schedules.len(), 1);
            assert_eq!(schedules[0], "BakerSchedule");
        },
        | _ => panic!("Expected Template declaration"),
    }
}

#[test]
fn test_template_with_behaviors_and_schedule() {
    let input = r#"
template Baker {
    include Person
    uses behaviors: BakingSkills, CustomerService
    uses schedule: BakerSchedule
    specialty: "bread"
    baking_skill: 0.0..1.0
}
"#;

    let lexer = Lexer::new(input);
    let parser = FileParser::new();
    let result = parser.parse(lexer);

    assert!(result.is_ok(), "Failed to parse: {:?}", result.err());

    let file = result.unwrap();
    match &file.declarations[0] {
        | Declaration::Template(t) => {
            assert_eq!(t.name, "Baker");

            // Check include
            assert_eq!(t.includes.len(), 1);
            assert_eq!(t.includes[0], "Person");

            // Check behavior links
            assert!(t.uses_behaviors.is_some());
            let behaviors = t.uses_behaviors.as_ref().unwrap();
            assert_eq!(behaviors.len(), 2);

            // Check schedule link
            assert!(t.uses_schedule.is_some());
            let schedules = t.uses_schedule.as_ref().unwrap();
            assert_eq!(schedules.len(), 1);
        },
        | _ => panic!("Expected Template declaration"),
    }
}
