//! Tests migrated from inline #[cfg(test)] module in src/core/engine/effect_context.rs

use cardgame::effects::{CreatureFilter, EffectTarget};
use cardgame::engine::{ResolvedTargets, TargetResolver};
use cardgame::keywords::Keywords;
use cardgame::state::{Creature, GameState};
use cardgame::types::{CardId, CreatureInstanceId, PlayerId, Slot};

fn create_test_creature(owner: PlayerId, slot: Slot) -> Creature {
    Creature {
        instance_id: CreatureInstanceId(1),
        card_id: CardId(1000),
        owner,
        slot,
        attack: 2,
        current_health: 3,
        max_health: 3,
        base_attack: 2,
        base_health: 3,
        keywords: Keywords::none(),
        status: Default::default(),
        turn_played: 1,
        frenzy_stacks: 0,
            temp_attack_bonus: 0,
        level: 0,
        progress: 0,
        token_data: None,
    }
}

#[test]
fn test_resolve_single_creature() {
    let mut state = GameState::default();
    state.players[0]
        .creatures
        .push(create_test_creature(PlayerId::PLAYER_ONE, Slot(0)));

    let target = EffectTarget::Creature {
        owner: PlayerId::PLAYER_ONE,
        slot: Slot(0),
    };
    let result = TargetResolver::resolve(&target, None, &state);

    match result {
        ResolvedTargets::Single { owner, slot } => {
            assert_eq!(owner, PlayerId::PLAYER_ONE);
            assert_eq!(slot, Slot(0));
        }
        _ => panic!("Expected Single target"),
    }
}

#[test]
fn test_resolve_nonexistent_creature() {
    let state = GameState::default();
    let target = EffectTarget::Creature {
        owner: PlayerId::PLAYER_ONE,
        slot: Slot(0),
    };
    let result = TargetResolver::resolve(&target, None, &state);

    assert!(matches!(result, ResolvedTargets::None));
}

#[test]
fn test_resolve_player() {
    let state = GameState::default();
    let target = EffectTarget::Player(PlayerId::PLAYER_TWO);
    let result = TargetResolver::resolve(&target, None, &state);

    match result {
        ResolvedTargets::Player(player) => assert_eq!(player, PlayerId::PLAYER_TWO),
        _ => panic!("Expected Player target"),
    }
}

#[test]
fn test_resolve_all_creatures() {
    let mut state = GameState::default();
    state.players[0]
        .creatures
        .push(create_test_creature(PlayerId::PLAYER_ONE, Slot(0)));
    state.players[0]
        .creatures
        .push(create_test_creature(PlayerId::PLAYER_ONE, Slot(1)));
    state.players[1]
        .creatures
        .push(create_test_creature(PlayerId::PLAYER_TWO, Slot(0)));

    let target = EffectTarget::AllCreatures;
    let result = TargetResolver::resolve(&target, None, &state);

    match result {
        ResolvedTargets::Multiple(creatures) => {
            assert_eq!(creatures.len(), 3);
        }
        _ => panic!("Expected Multiple targets"),
    }
}

#[test]
fn test_resolve_ally_creatures() {
    let mut state = GameState::default();
    state.players[0]
        .creatures
        .push(create_test_creature(PlayerId::PLAYER_ONE, Slot(0)));
    state.players[0]
        .creatures
        .push(create_test_creature(PlayerId::PLAYER_ONE, Slot(1)));
    state.players[1]
        .creatures
        .push(create_test_creature(PlayerId::PLAYER_TWO, Slot(0)));

    let target = EffectTarget::AllAllyCreatures(PlayerId::PLAYER_ONE);
    let result = TargetResolver::resolve(&target, None, &state);

    match result {
        ResolvedTargets::Multiple(creatures) => {
            assert_eq!(creatures.len(), 2);
            assert!(creatures
                .iter()
                .all(|(owner, _)| *owner == PlayerId::PLAYER_ONE));
        }
        _ => panic!("Expected Multiple targets"),
    }
}

#[test]
fn test_resolve_enemy_creatures() {
    let mut state = GameState::default();
    state.players[0]
        .creatures
        .push(create_test_creature(PlayerId::PLAYER_ONE, Slot(0)));
    state.players[1]
        .creatures
        .push(create_test_creature(PlayerId::PLAYER_TWO, Slot(0)));
    state.players[1]
        .creatures
        .push(create_test_creature(PlayerId::PLAYER_TWO, Slot(1)));

    let target = EffectTarget::AllEnemyCreatures(PlayerId::PLAYER_ONE);
    let result = TargetResolver::resolve(&target, None, &state);

    match result {
        ResolvedTargets::Multiple(creatures) => {
            assert_eq!(creatures.len(), 2);
            assert!(creatures
                .iter()
                .all(|(owner, _)| *owner == PlayerId::PLAYER_TWO));
        }
        _ => panic!("Expected Multiple targets"),
    }
}

// =============================================================================
// M4: filter on single-target EffectTarget::Creature
// =============================================================================

#[test]
fn filter_passes_single_target_matching_creature() {
    // A Creature with 3 health should resolve when filter requires max_health >= 3
    let mut state = GameState::default();
    let mut c = create_test_creature(PlayerId::PLAYER_ONE, Slot(0));
    c.current_health = 3;
    state.players[0].creatures.push(c);

    let target = EffectTarget::Creature { owner: PlayerId::PLAYER_ONE, slot: Slot(0) };
    let filter = CreatureFilter { max_health: Some(4), ..Default::default() };
    let result = TargetResolver::resolve(&target, Some(&filter), &state);

    assert!(matches!(result, ResolvedTargets::Single { .. }), "creature with health 3 should pass max_health=4 filter");
}

#[test]
fn filter_blocks_single_target_exceeding_max_health() {
    // A Creature with 5 health should be blocked when filter requires max_health=4
    let mut state = GameState::default();
    let mut c = create_test_creature(PlayerId::PLAYER_ONE, Slot(0));
    c.current_health = 5;
    state.players[0].creatures.push(c);

    let target = EffectTarget::Creature { owner: PlayerId::PLAYER_ONE, slot: Slot(0) };
    let filter = CreatureFilter { max_health: Some(4), ..Default::default() };
    let result = TargetResolver::resolve(&target, Some(&filter), &state);

    assert!(matches!(result, ResolvedTargets::None), "creature with health 5 should be blocked by max_health=4 filter");
}

#[test]
fn filter_blocks_enemy_slot_or_face_when_creature_fails_filter() {
    // EnemySlotOrFace: creature exists but fails filter → should NOT fall through to face damage
    let mut state = GameState::default();
    let mut c = create_test_creature(PlayerId::PLAYER_TWO, Slot(0));
    c.current_health = 7;
    state.players[1].creatures.push(c);

    let target = EffectTarget::EnemySlotOrFace { owner: PlayerId::PLAYER_TWO, slot: Slot(0) };
    let filter = CreatureFilter { max_health: Some(4), ..Default::default() };
    let result = TargetResolver::resolve(&target, Some(&filter), &state);

    assert!(matches!(result, ResolvedTargets::None),
        "filtered-out creature in EnemySlotOrFace should not fall through to Player target");
}

#[test]
fn enemy_slot_or_face_falls_through_to_player_when_slot_empty() {
    // EnemySlotOrFace: no creature → should resolve to Player (face damage), filter irrelevant
    let state = GameState::default();

    let target = EffectTarget::EnemySlotOrFace { owner: PlayerId::PLAYER_TWO, slot: Slot(0) };
    let filter = CreatureFilter { max_health: Some(4), ..Default::default() };
    let result = TargetResolver::resolve(&target, Some(&filter), &state);

    assert!(matches!(result, ResolvedTargets::Player(p) if p == PlayerId::PLAYER_TWO),
        "empty EnemySlotOrFace slot should still resolve to face damage");
}
