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

use cardgame::bots::BotType;
use cardgame::cards::CardDatabase;
use cardgame::decks::{DeckRegistry, Faction};
use cardgame::execution::GameData;
use cardgame::validation::{
    ArchetypeWeights, BalanceAnalyzer, BalanceStatus, GameDiagnosticCollector, GameDiagnosticData,
    MatchupDiagnostics, MatchupResult, ValidationExecutor,
};

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

fn load_test_data() -> GameData {
    GameData::load_default(true).expect("Failed to load test data")
}

fn create_test_matchup(
    f1: &str,
    f2: &str,
    f1_wins: u32,
    f2_wins: u32,
    draws: u32,
) -> MatchupResult {
    let total = f1_wins + f2_wins + draws;
    let decisive = total - draws;
    MatchupResult {
        faction1: f1.to_string(),
        faction2: f2.to_string(),
        deck1_id: format!("{}_deck", f1),
        deck2_id: format!("{}_deck", f2),
        commander1_id: 5000,
        commander2_id: 5001,
        commander1_name: format!("{} Commander", f1),
        commander2_name: format!("{} Commander", f2),
        f1_as_p1_wins: f1_wins / 2,
        f1_as_p1_games: total / 2,
        f1_as_p2_wins: f1_wins - f1_wins / 2,
        f1_as_p2_games: total / 2,
        faction1_total_wins: f1_wins,
        faction2_total_wins: f2_wins,
        draws,
        dir1_draws: draws / 2,
        dir2_draws: draws - draws / 2,
        total_games: total,
        faction1_win_rate: if decisive > 0 {
            f1_wins as f64 / decisive as f64
        } else {
            0.5
        },
        faction2_win_rate: if decisive > 0 {
            f2_wins as f64 / decisive as f64
        } else {
            0.5
        },
        avg_turns: 25.0,
        total_time_secs: 1.0,
        diagnostics: MatchupDiagnostics::default(),
    }
}

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

#[test]
fn test_run_single_matchup() {
    let data = load_test_data();
    let builder = cardgame::execution::MatchupBuilder::new(&data.deck_registry);

    let matchups = builder.build_faction_matchups(Faction::Argentum, Faction::Symbiote);
    let matchup = &matchups[0];

    let executor = ValidationExecutor::new(&data.card_db, 10).with_bot_type(BotType::Greedy);
    let archetype_weights = ArchetypeWeights::new();

    let result = executor.run_matchup(matchup, &archetype_weights, 2, 42);

    assert_eq!(result.total_games, 4);
    assert!(result.faction1_win_rate >= 0.0 && result.faction1_win_rate <= 1.0);
    assert!(result.commander1_id > 0);
    assert!(result.commander2_id > 0);
    assert!(!result.commander1_name.is_empty());
    assert!(!result.commander2_name.is_empty());
}

#[test]
fn test_commanders_are_used() {
    let data = load_test_data();

    let argentum_decks = data.deck_registry.decks_for_faction(Faction::Argentum);
    let symbiote_decks = data.deck_registry.decks_for_faction(Faction::Symbiote);

    assert!(!argentum_decks.is_empty());
    assert!(!symbiote_decks.is_empty());

    let matchup = cardgame::execution::UnifiedMatchup::new(
        argentum_decks[0].clone(),
        symbiote_decks[0].clone(),
    );

    assert_eq!(matchup.commander1().0, argentum_decks[0].commander);
    assert_eq!(matchup.commander2().0, symbiote_decks[0].commander);

    let executor = ValidationExecutor::new(&data.card_db, 10).with_bot_type(BotType::Greedy);
    let archetype_weights = ArchetypeWeights::new();
    let result = executor.run_matchup(&matchup, &archetype_weights, 1, 42);

    assert_eq!(result.commander1_id, argentum_decks[0].commander);
    assert_eq!(result.commander2_id, symbiote_decks[0].commander);
}

#[test]
fn test_archetype_weights_loading() {
    let weights_path = cardgame::data_dir().join("weights");
    let weights = ArchetypeWeights::load_from_directory(&weights_path, true);

    assert!(weights.get("aggro").is_some() || weights.get("control").is_some());
}

// ── matchup.rs (validation) ─────────────────────────────────────────────────

#[test]
fn test_validation_build_faction_matchups() {
    use cardgame::validation::MatchupBuilder;

    let card_db = {
        let cards_path = cardgame::data_dir().join("cards/core_set");
        let commanders_path = cardgame::data_dir().join("commanders");
        CardDatabase::load_from_directory(cards_path)
            .unwrap()
            .with_commanders(
                CardDatabase::load_commanders_from_directory(commanders_path).unwrap(),
            )
    };
    let registry = {
        let decks_path = cardgame::data_dir().join("decks");
        DeckRegistry::load_from_directory(decks_path).unwrap()
    };

    let builder = MatchupBuilder::new(&registry, &card_db);
    let matchups = builder.build_faction_matchups();

    assert_eq!(matchups.len(), 3);
    for m in &matchups {
        assert!(!m.deck1_cards.is_empty());
        assert!(!m.deck2_cards.is_empty());
    }
}

#[test]
fn test_validation_filter_matchups_exact() {
    use cardgame::validation::{filter_matchups, MatchupBuilder};

    let card_db = {
        let cards_path = cardgame::data_dir().join("cards/core_set");
        let commanders_path = cardgame::data_dir().join("commanders");
        CardDatabase::load_from_directory(cards_path)
            .unwrap()
            .with_commanders(
                CardDatabase::load_commanders_from_directory(commanders_path).unwrap(),
            )
    };
    let registry = {
        let decks_path = cardgame::data_dir().join("decks");
        DeckRegistry::load_from_directory(decks_path).unwrap()
    };

    let builder = MatchupBuilder::new(&registry, &card_db);
    let matchups = builder.build_faction_matchups();
    let filtered = filter_matchups(matchups, "argentum-symbiote");

    assert_eq!(filtered.len(), 1);
    assert!(
        (filtered[0].faction1 == Faction::Argentum && filtered[0].faction2 == Faction::Symbiote)
            || (filtered[0].faction1 == Faction::Symbiote
                && filtered[0].faction2 == Faction::Argentum)
    );
}

#[test]
fn test_validation_filter_matchups_single_faction() {
    use cardgame::validation::{filter_matchups, MatchupBuilder};

    let card_db = {
        let cards_path = cardgame::data_dir().join("cards/core_set");
        let commanders_path = cardgame::data_dir().join("commanders");
        CardDatabase::load_from_directory(cards_path)
            .unwrap()
            .with_commanders(
                CardDatabase::load_commanders_from_directory(commanders_path).unwrap(),
            )
    };
    let registry = {
        let decks_path = cardgame::data_dir().join("decks");
        DeckRegistry::load_from_directory(decks_path).unwrap()
    };

    let builder = MatchupBuilder::new(&registry, &card_db);
    let matchups = builder.build_faction_matchups();
    let filtered = filter_matchups(matchups, "argentum");

    assert_eq!(filtered.len(), 2);
}

#[test]
fn test_validation_build_all_deck_matchups() {
    use cardgame::validation::MatchupBuilder;

    let card_db = {
        let cards_path = cardgame::data_dir().join("cards/core_set");
        let commanders_path = cardgame::data_dir().join("commanders");
        CardDatabase::load_from_directory(cards_path)
            .unwrap()
            .with_commanders(
                CardDatabase::load_commanders_from_directory(commanders_path).unwrap(),
            )
    };
    let registry = {
        let decks_path = cardgame::data_dir().join("decks");
        DeckRegistry::load_from_directory(decks_path).unwrap()
    };

    let builder = MatchupBuilder::new(&registry, &card_db);
    let matchups = builder.build_all_deck_matchups();
    let single_matchups = builder.build_faction_matchups();

    assert!(matchups.len() >= single_matchups.len());

    for m in &matchups {
        assert!(!m.deck1_cards.is_empty());
        assert!(!m.deck2_cards.is_empty());
    }
}

// ── game_diagnostics.rs ──────────────────────────────────────────────────────

#[test]
fn test_collector_initialization() {
    let collector = GameDiagnosticCollector::new();
    let data = collector.finalize();

    assert!(data.first_blood.is_none());
    assert_eq!(data.p1_face_damage, 0);
    assert_eq!(data.p2_face_damage, 0);
    assert_eq!(data.turn_count, 0);
}

#[test]
fn test_game_diagnostic_data_default() {
    let data = GameDiagnosticData::default();
    assert!(data.first_blood.is_none());
    assert_eq!(data.board_advantage_sum, 0.0);
}

// ── analyzer.rs ──────────────────────────────────────────────────────────────

#[test]
fn test_balanced_results() {
    let matchups = vec![
        create_test_matchup("argentum", "symbiote", 50, 50, 0),
        create_test_matchup("argentum", "obsidion", 50, 50, 0),
        create_test_matchup("symbiote", "obsidion", 50, 50, 0),
    ];

    let analyzer = BalanceAnalyzer::new();
    let summary = analyzer.analyze(&matchups);

    assert_eq!(summary.faction_status, BalanceStatus::Balanced);
    assert!(summary.max_faction_delta < 0.01);
}

#[test]
fn test_imbalanced_faction() {
    let matchups = vec![
        create_test_matchup("argentum", "symbiote", 80, 20, 0),
        create_test_matchup("argentum", "obsidion", 80, 20, 0),
        create_test_matchup("symbiote", "obsidion", 50, 50, 0),
    ];

    let analyzer = BalanceAnalyzer::new();
    let summary = analyzer.analyze(&matchups);

    assert!(summary.max_faction_delta > 0.15);
    assert_eq!(summary.faction_status, BalanceStatus::Imbalanced);
}

#[test]
fn test_p1_advantage() {
    let mut matchups = vec![create_test_matchup("argentum", "symbiote", 50, 50, 0)];
    matchups[0].f1_as_p1_wins = 45;
    matchups[0].f1_as_p2_wins = 5;

    let analyzer = BalanceAnalyzer::new();
    let summary = analyzer.analyze(&matchups);

    assert!(summary.p1_win_rate > 0.6 || summary.p1_win_rate < 0.4);
}

// ── report.rs ────────────────────────────────────────────────────────────────

#[test]
fn test_capitalize() {
    use cardgame::validation::capitalize;

    assert_eq!(capitalize("argentum"), "Argentum");
    assert_eq!(capitalize("SYMBIOTE"), "SYMBIOTE");
    assert_eq!(capitalize(""), "");
    assert_eq!(capitalize("a"), "A");
}
