//! Tests for year-long composable schedule system

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

#[test]
fn test_simple_schedule_backward_compat() {
    let input = r#"
schedule DailyRoutine {
    09:00 -> 17:00 : work {
        place: "Office"
    }
    18:00 -> 19:00 : dinner {}
}
"#;

    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::Schedule(s) => {
            assert_eq!(s.name, "DailyRoutine");
            assert!(s.modifies.is_none());
            assert_eq!(s.blocks.len(), 2);
            assert_eq!(s.recurrences.len(), 0);

            // First block
            assert_eq!(s.blocks[0].activity, "work");
            assert!(s.blocks[0].name.is_none());
            assert!(!s.blocks[0].is_override);
        },
        | _ => panic!("Expected Schedule declaration"),
    }
}

#[test]
fn test_schedule_modifies() {
    let input = r#"
schedule BakerSchedule modifies BaseWorkday {
    block work { 05:00 -> 13:00, action: BakingWork }
}
"#;

    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::Schedule(s) => {
            assert_eq!(s.name, "BakerSchedule");
            assert_eq!(s.modifies, Some("BaseWorkday".to_string()));
        },
        | _ => panic!("Expected Schedule declaration"),
    }
}

#[test]
fn test_named_block_with_action() {
    let input = r#"
schedule WorkSchedule {
    block work { 09:00 -> 17:00, action: WorkBehavior }
    block lunch { 12:00 -> 13:00, action: EatLunch }
}
"#;

    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::Schedule(s) => {
            assert_eq!(s.blocks.len(), 2);

            // First block
            assert_eq!(s.blocks[0].name, Some("work".to_string()));
            assert!(!s.blocks[0].is_override);
            assert_eq!(s.blocks[0].action, Some(vec!["WorkBehavior".to_string()]));
            assert_eq!(s.blocks[0].start.hour, 9);
            assert_eq!(s.blocks[0].end.hour, 17);

            // Second block
            assert_eq!(s.blocks[1].name, Some("lunch".to_string()));
            assert_eq!(s.blocks[1].action, Some(vec!["EatLunch".to_string()]));
        },
        | _ => panic!("Expected Schedule declaration"),
    }
}

#[test]
fn test_override_block() {
    let input = r#"
schedule BakerSchedule modifies BaseWorkday {
    override work { 05:00 -> 13:00, action: BakingWork }
    block prep { 03:00 -> 05:00, action: PrepBread }
}
"#;

    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::Schedule(s) => {
            assert_eq!(s.blocks.len(), 2);

            // Override block
            assert_eq!(s.blocks[0].name, Some("work".to_string()));
            assert!(s.blocks[0].is_override);
            assert_eq!(s.blocks[0].action, Some(vec!["BakingWork".to_string()]));

            // Regular named block
            assert_eq!(s.blocks[1].name, Some("prep".to_string()));
            assert!(!s.blocks[1].is_override);
        },
        | _ => panic!("Expected Schedule declaration"),
    }
}

#[test]
fn test_recurrence_pattern() {
    let input = r#"
schedule WeeklySchedule {
    recurrence MarketDay on Earthday {
        block market { 08:00 -> 13:00, action: SellAtMarket }
        block restock { 14:00 -> 16:00, action: RestockGoods }
    }
}
"#;

    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::Schedule(s) => {
            assert_eq!(s.recurrences.len(), 1);

            let recurrence = &s.recurrences[0];
            assert_eq!(recurrence.name, "MarketDay");
            assert_eq!(
                recurrence.constraint,
                TemporalConstraint::DayOfWeek("Earthday".to_string())
            );
            assert_eq!(recurrence.blocks.len(), 2);

            // First block in recurrence
            assert_eq!(recurrence.blocks[0].name, Some("market".to_string()));
            assert_eq!(
                recurrence.blocks[0].action,
                Some(vec!["SellAtMarket".to_string()])
            );
        },
        | _ => panic!("Expected Schedule declaration"),
    }
}

#[test]
fn test_qualified_path_action() {
    let input = r#"
schedule WorkSchedule {
    block work { 09:00 -> 17:00, action: village::baker::BakingWork }
}
"#;

    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::Schedule(s) => {
            assert_eq!(
                s.blocks[0].action,
                Some(vec![
                    "village".to_string(),
                    "baker".to_string(),
                    "BakingWork".to_string()
                ])
            );
        },
        | _ => panic!("Expected Schedule declaration"),
    }
}

#[test]
fn test_mixed_blocks_and_recurrences() {
    let input = r#"
schedule CompleteSchedule modifies BaseSchedule {
    block morning { 06:00 -> 12:00, action: MorningRoutine }

    recurrence Weekend on Spiritday {
        block leisure { 10:00 -> 18:00, action: RelaxAndPlay }
    }

    override evening { 18:00 -> 22:00, action: EveningRoutine }
}
"#;

    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::Schedule(s) => {
            assert_eq!(s.name, "CompleteSchedule");
            assert_eq!(s.modifies, Some("BaseSchedule".to_string()));
            assert_eq!(s.blocks.len(), 2); // morning and override evening
            assert_eq!(s.recurrences.len(), 1); // Weekend

            // Check we have both regular and override blocks
            let has_regular = s.blocks.iter().any(|b| !b.is_override);
            let has_override = s.blocks.iter().any(|b| b.is_override);
            assert!(has_regular && has_override);
        },
        | _ => panic!("Expected Schedule declaration"),
    }
}

#[test]
fn test_block_with_fields() {
    let input = r#"
schedule WorkSchedule {
    block work {
        09:00 -> 17:00
        action: WorkBehavior
        intensity: "high"
        place: "office"
    }
}
"#;

    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::Schedule(s) => {
            assert_eq!(s.blocks[0].fields.len(), 2); // intensity and place
            assert_eq!(s.blocks[0].action, Some(vec!["WorkBehavior".to_string()]));
        },
        | _ => panic!("Expected Schedule declaration"),
    }
}

#[test]
fn test_empty_schedule() {
    let input = r#"
schedule EmptySchedule {
}
"#;

    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::Schedule(s) => {
            assert_eq!(s.blocks.len(), 0);
            assert_eq!(s.recurrences.len(), 0);
        },
        | _ => panic!("Expected Schedule declaration"),
    }
}

#[test]
fn test_schedule_only_recurrences() {
    let input = r#"
schedule EventSchedule {
    recurrence Festival on FirstDayOfSummer {
        block celebration { 10:00 -> 22:00, action: Celebrate }
    }
    recurrence MarketDay on Earthday {
        block market { 08:00 -> 14:00, action: TradingBehavior }
    }
}
"#;

    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::Schedule(s) => {
            assert_eq!(s.blocks.len(), 0);
            assert_eq!(s.recurrences.len(), 2);
        },
        | _ => panic!("Expected Schedule declaration"),
    }
}
