//! Tests migrated from inline #[cfg(test)] modules in src/arena/*.rs

use cardgame::arena::{
    EloTracker, MatchConfig, MatchOutcome, MatchupStats, Participant, SequentialConfig,
    SwissConfig, TournamentMatchResult,
};
use cardgame::bots::BotType;
use cardgame::cards::CardDatabase;
use cardgame::decks::{DeckDefinition, DeckRegistry, Faction};

// ── helpers ──────────────────────────────────────────────────────────────────

fn test_card_db() -> CardDatabase {
    let cards_path = cardgame::data_dir().join("cards/core_set");
    let commanders_path = cardgame::data_dir().join("commanders");
    CardDatabase::load_with_commanders(cards_path, commanders_path).unwrap()
}

fn test_deck_definition() -> DeckDefinition {
    DeckDefinition {
        id: "test".to_string(),
        name: "Test Deck".to_string(),
        description: String::new(),
        playstyle: String::new(),
        commander: 5000,
        cards: vec![1000, 1000, 1001, 1001, 1002, 1002, 1003, 1003, 1004, 1004],
        tags: vec![],
    }
}

// ── executor.rs ──────────────────────────────────────────────────────────────

#[test]
fn test_parallel_execution() {
    use cardgame::arena::run_match_parallel;

    let card_db = test_card_db();
    let config = MatchConfig::new(
        BotType::Random,
        BotType::Random,
        test_deck_definition(),
        test_deck_definition(),
        5,
        42,
    );

    let stats = run_match_parallel(&card_db, &config).expect("Game init should succeed");
    assert_eq!(stats.overall.games, 5);
}

#[test]
fn test_sequential_execution() {
    use cardgame::arena::run_match_sequential;

    let card_db = test_card_db();
    let config = MatchConfig::new(
        BotType::Random,
        BotType::Random,
        test_deck_definition(),
        test_deck_definition(),
        3,
        42,
    );
    let seq_config = SequentialConfig::new();
    let mut logger = None;

    let stats = run_match_sequential(&card_db, &config, &seq_config, &mut logger)
        .expect("Game init should succeed");
    assert_eq!(stats.overall.games, 3);
}

// ── deck_utils.rs ────────────────────────────────────────────────────────────

#[test]
fn test_load_deck_not_found() {
    use cardgame::arena::load_deck;

    let registry = DeckRegistry::new();
    let cards_path = cardgame::data_dir().join("cards/core_set");
    let card_db = CardDatabase::load_from_directory(cards_path).unwrap();
    let result = load_deck(Some("nonexistent"), &registry, &card_db, "1");
    assert!(result.is_err());
    assert!(result.unwrap_err().contains("not found"));
}

#[test]
fn test_load_deck_none_returns_error() {
    use cardgame::arena::load_deck;

    let registry = DeckRegistry::new();
    let cards_path = cardgame::data_dir().join("cards/core_set");
    let card_db = CardDatabase::load_from_directory(cards_path).unwrap();
    let result = load_deck(None, &registry, &card_db, "1");
    assert!(result.is_err());
    assert!(result.unwrap_err().contains("No deck specified"));
}

#[test]
fn test_validate_faction_binding_random_bot() {
    use cardgame::arena::validate_faction_deck_binding;

    let registry = DeckRegistry::new();
    let result =
        validate_faction_deck_binding(&BotType::Random, Some("architect_fortify"), &registry, "Bot 1");
    assert!(result.is_none());
}

#[test]
fn test_validate_faction_binding_no_deck() {
    use cardgame::arena::validate_faction_deck_binding;

    let registry = DeckRegistry::new();
    let result = validate_faction_deck_binding(
        &BotType::AgentSpecialist(Faction::Argentum),
        None,
        &registry,
        "Bot 1",
    );
    assert!(result.is_none());
}

// ── tournament.rs ────────────────────────────────────────────────────────────

#[test]
fn test_recommended_rounds() {
    assert_eq!(SwissConfig::recommended_rounds(1), 0);
    assert_eq!(SwissConfig::recommended_rounds(2), 2);
    assert_eq!(SwissConfig::recommended_rounds(4), 3);
    assert_eq!(SwissConfig::recommended_rounds(8), 4);
    assert_eq!(SwissConfig::recommended_rounds(12), 5);
}

#[test]
fn test_match_outcome_inverse() {
    let outcome = MatchOutcome {
        result: TournamentMatchResult::Win,
        wins: 7,
        losses: 3,
        draws: 0,
        games: 10,
        win_rate: 0.7,
    };

    let inverse = outcome.inverse();
    assert_eq!(inverse.result, TournamentMatchResult::Loss);
    assert_eq!(inverse.wins, 3);
    assert_eq!(inverse.losses, 7);
    assert_eq!(inverse.games, 10);
}

#[test]
fn test_participant_record_match() {
    let deck = DeckDefinition {
        id: "test_deck".to_string(),
        name: "Test Deck".to_string(),
        description: "Test deck for unit tests".to_string(),
        commander: 1000,
        cards: vec![],
        tags: vec![],
        playstyle: "midrange".to_string(),
    };

    let mut participant = Participant::new(deck);
    assert_eq!(participant.score, 0);

    let outcome = MatchOutcome {
        result: TournamentMatchResult::Win,
        wins: 7,
        losses: 3,
        draws: 0,
        games: 10,
        win_rate: 0.7,
    };
    participant.record_match("opponent1", outcome);
    assert_eq!(participant.score, 3);
    assert!(participant.has_played("opponent1"));

    let outcome2 = MatchOutcome {
        result: TournamentMatchResult::Draw,
        wins: 5,
        losses: 5,
        draws: 0,
        games: 10,
        win_rate: 0.5,
    };
    participant.record_match("opponent2", outcome2);
    assert_eq!(participant.score, 4);

    let outcome3 = MatchOutcome {
        result: TournamentMatchResult::Loss,
        wins: 3,
        losses: 7,
        draws: 0,
        games: 10,
        win_rate: 0.3,
    };
    participant.record_match("opponent3", outcome3);
    assert_eq!(participant.score, 4);
}

// ── rating.rs ────────────────────────────────────────────────────────────────

#[test]
fn test_rating_update() {
    let tmp = std::env::temp_dir().join("cardgame_test_elo.json");
    let _ = std::fs::remove_file(&tmp);
    let mut tracker = EloTracker::load_or_create(&tmp);

    let stats = MatchupStats {
        games: 10,
        bot1_wins: 8,
        bot2_wins: 2,
        draws: 0,
        total_turns: 150,
        total_time: std::time::Duration::from_secs(10),
    };

    let (delta1, delta2) = tracker.update_match("deck_a", "deck_b", &stats);

    assert!(delta1 > 0);
    assert!(delta2 < 0);

    let default_rating = cardgame::arena::rating::DEFAULT_RATING;
    assert!(tracker.get_rating("deck_a") > default_rating);
    assert!(tracker.get_rating("deck_b") < default_rating);

    let deck_a = tracker.get_deck_rating("deck_a").unwrap();
    assert_eq!(deck_a.games, 10);
    assert_eq!(deck_a.wins, 8);
    assert_eq!(deck_a.losses, 2);

    let _ = std::fs::remove_file(&tmp);
}

#[test]
fn test_draw_handling() {
    let tmp = std::env::temp_dir().join("cardgame_test_elo_draw.json");
    let _ = std::fs::remove_file(&tmp);
    let mut tracker = EloTracker::load_or_create(&tmp);

    let stats = MatchupStats {
        games: 10,
        bot1_wins: 0,
        bot2_wins: 0,
        draws: 10,
        total_turns: 150,
        total_time: std::time::Duration::from_secs(10),
    };

    let (delta1, delta2) = tracker.update_match("deck_a", "deck_b", &stats);
    assert_eq!(delta1, 0);
    assert_eq!(delta2, 0);

    let _ = std::fs::remove_file(&tmp);
}
