use rsstacker::config::Config;
use rsstacker::modes::{
    Game, GameStats, Mode, Outcome, SCORE_ATTACK_TIME_FRAMES, outcome_for, stat_lines_for,
    summary_lines_for,
};

#[test]
fn outcome_rules_per_mode() {
    assert_eq!(outcome_for(Mode::Endless, true, 5, 100), Outcome::ToppedOut);
    assert_eq!(
        outcome_for(Mode::LineRace, true, 5, 100),
        Outcome::ToppedOut
    );
    assert_eq!(
        outcome_for(Mode::ScoreAttack, true, 5, 100),
        Outcome::ToppedOut
    );
    assert_eq!(
        outcome_for(Mode::Endless, false, 999, 999_999),
        Outcome::Running
    );
    assert_eq!(outcome_for(Mode::LineRace, false, 39, 0), Outcome::Running);
    assert_eq!(outcome_for(Mode::LineRace, false, 40, 0), Outcome::Cleared);
    assert_eq!(
        outcome_for(Mode::ScoreAttack, false, 5, SCORE_ATTACK_TIME_FRAMES - 1),
        Outcome::Running
    );
    assert_eq!(
        outcome_for(Mode::ScoreAttack, false, 5, SCORE_ATTACK_TIME_FRAMES),
        Outcome::Cleared
    );
}

#[test]
fn stat_and_summary_text_is_mode_aware() {
    let s = GameStats {
        lines: 12,
        pieces: 30,
        frames: 600,
        score: 4500,
        pps: 3.0,
    };
    let line_race = stat_lines_for(Mode::LineRace, &s).join("\n");
    assert!(line_race.contains("12/40"));
    let score_attack = stat_lines_for(Mode::ScoreAttack, &s).join("\n");
    assert!(score_attack.contains("Score") && score_attack.contains("4500"));
    assert!(score_attack.contains("Time") || score_attack.contains("Left"));
    let fin = summary_lines_for(Mode::LineRace, &s, Outcome::Cleared).join("\n");
    assert!(fin.contains("Finished") || fin.contains("inished"));
    let dead = summary_lines_for(Mode::Endless, &s, Outcome::ToppedOut).join("\n");
    assert!(dead.contains("Topped") || dead.contains("Game Over") || dead.contains("Score"));
}

#[test]
fn game_constructs_and_line_race_clears_when_lines_reach_40() {
    let config = Config::default();
    let mut game = Game::new(Mode::LineRace, &config, 12345);
    assert!(game.engine.board.current.is_some());
    assert_eq!(game.outcome(), Outcome::Running);
    game.engine.board.lines_cleared = 40;
    assert_eq!(game.outcome(), Outcome::Cleared);
}

#[test]
fn line_race_has_zero_gravity_and_timed_modes_have_curves() {
    let config = Config::default();
    assert!(Mode::LineRace.engine_config(&config).gravity.is_none());
    assert!(Mode::ScoreAttack.engine_config(&config).gravity.is_some());
    assert!(Mode::Endless.engine_config(&config).gravity.is_some());
}
