//! Unit tests for GameEngine methods not covered by existing test files.
//!
//! Covers: get_commander_def(), apply_action_with_tracers(), remove_support()

use cardgame::actions::Action;
use cardgame::engine::GameEngine;
use cardgame::types::{CardId, PlayerId, Slot};

use super::common::{
    card_playing_test_db, load_real_card_db, load_real_deck_registry,
    setup_test_essence, simple_deck, start_test_game,
};

// ── get_commander_def ────────────────────────────────────────────────────────

#[test]
fn test_get_commander_def_returns_commander_for_both_players() {
    let card_db = load_real_card_db();
    let registry = load_real_deck_registry();
    let decks: Vec<_> = registry.decks().collect();

    let mut engine = GameEngine::new(&card_db);
    engine.start_game(decks[0], decks[1], 42).unwrap();

    let p1_commander = engine.get_commander_def(PlayerId::PLAYER_ONE);
    let p2_commander = engine.get_commander_def(PlayerId::PLAYER_TWO);

    assert!(p1_commander.is_some(), "P1 should have a commander");
    assert!(p2_commander.is_some(), "P2 should have a commander");

    let p1 = p1_commander.unwrap();
    let p2 = p2_commander.unwrap();
    assert!(!p1.name.is_empty());
    assert!(!p2.name.is_empty());
}

#[test]
fn test_get_commander_def_matches_deck_commander() {
    let card_db = load_real_card_db();
    let registry = load_real_deck_registry();
    let decks: Vec<_> = registry.decks().collect();

    let mut engine = GameEngine::new(&card_db);
    engine.start_game(decks[0], decks[1], 42).unwrap();

    let p1_commander = engine.get_commander_def(PlayerId::PLAYER_ONE).unwrap();
    assert_eq!(p1_commander.id, decks[0].commander);

    let p2_commander = engine.get_commander_def(PlayerId::PLAYER_TWO).unwrap();
    assert_eq!(p2_commander.id, decks[1].commander);
}

// ── apply_action_with_tracers ────────────────────────────────────────────────

#[test]
fn test_apply_action_with_combat_tracer() {
    use cardgame::arena::CombatTracer;

    let card_db = load_real_card_db();
    let registry = load_real_deck_registry();
    let decks: Vec<_> = registry.decks().collect();

    let mut engine = GameEngine::new(&card_db);
    engine.start_game(decks[0], decks[1], 42).unwrap();

    let mut tracer = CombatTracer::new(true);

    // Apply an end_turn action with tracer — should not panic
    let result = engine.apply_action_with_tracers(
        Action::EndTurn,
        Some(&mut tracer),
        None,
    );
    assert!(result.is_ok());
}

#[test]
fn test_apply_action_with_effect_tracer() {
    use cardgame::arena::EffectTracer;

    let card_db = load_real_card_db();
    let registry = load_real_deck_registry();
    let decks: Vec<_> = registry.decks().collect();

    let mut engine = GameEngine::new(&card_db);
    engine.start_game(decks[0], decks[1], 42).unwrap();

    let mut tracer = EffectTracer::new(true);

    let result = engine.apply_action_with_tracers(
        Action::EndTurn,
        None,
        Some(&mut tracer),
    );
    assert!(result.is_ok());
}

#[test]
fn test_apply_action_with_both_tracers() {
    use cardgame::arena::{CombatTracer, EffectTracer};

    let card_db = load_real_card_db();
    let registry = load_real_deck_registry();
    let decks: Vec<_> = registry.decks().collect();

    let mut engine = GameEngine::new(&card_db);
    engine.start_game(decks[0], decks[1], 42).unwrap();

    let mut combat_tracer = CombatTracer::new(true);
    let mut effect_tracer = EffectTracer::new(true);

    let result = engine.apply_action_with_tracers(
        Action::EndTurn,
        Some(&mut combat_tracer),
        Some(&mut effect_tracer),
    );
    assert!(result.is_ok());
}

// ── remove_support ───────────────────────────────────────────────────────────

#[test]
fn test_remove_support_clears_slot() {
    let card_db = card_playing_test_db();
    let deck = simple_deck();
    let mut engine = GameEngine::new(&card_db);
    start_test_game(&mut engine, deck.clone(), deck, 42);

    let player = engine.state.active_player;
    setup_test_essence(&mut engine.state, player, 10);

    // Give player a support card (id 6 = Test Support) in hand
    engine.state.players[player.index()].hand.clear();
    engine.state.players[player.index()]
        .hand
        .push(cardgame::state::CardInstance::new(CardId(6)));

    // Play support to slot 0
    engine
        .apply_action(Action::PlayCard {
            hand_index: 0,
            slot: Slot(0),
        })
        .unwrap();

    assert!(
        engine.state.players[player.index()].get_support(Slot(0)).is_some(),
        "Support should be in slot 0"
    );

    // Remove the support
    engine.remove_support(player, Slot(0));

    assert!(
        engine.state.players[player.index()].get_support(Slot(0)).is_none(),
        "Support slot should be empty after removal"
    );
}

#[test]
fn test_remove_support_reverts_attack_bonus() {
    let card_db = card_playing_test_db();
    let deck = simple_deck();
    let mut engine = GameEngine::new(&card_db);
    start_test_game(&mut engine, deck.clone(), deck, 42);

    let player = engine.state.active_player;
    setup_test_essence(&mut engine.state, player, 10);

    // Place a creature first (id 1 = 2/3 Test Creature)
    engine.state.players[player.index()].hand.clear();
    engine.state.players[player.index()]
        .hand
        .push(cardgame::state::CardInstance::new(CardId(1)));
    engine
        .apply_action(Action::PlayCard {
            hand_index: 0,
            slot: Slot(0),
        })
        .unwrap();

    let base_attack = engine.state.players[player.index()].creatures[0].attack;

    // Place War Banner (id 10 = +1 attack passive)
    engine.state.players[player.index()]
        .hand
        .push(cardgame::state::CardInstance::new(CardId(10)));
    engine
        .apply_action(Action::PlayCard {
            hand_index: 0,
            slot: Slot(0),
        })
        .unwrap();

    let buffed_attack = engine.state.players[player.index()].creatures[0].attack;
    assert_eq!(
        buffed_attack,
        base_attack + 1,
        "Creature should have +1 attack from War Banner"
    );

    // Remove the support
    engine.remove_support(player, Slot(0));

    let final_attack = engine.state.players[player.index()].creatures[0].attack;
    assert_eq!(
        final_attack, base_attack,
        "Creature attack should revert after support removal"
    );
}
