import numpy as np
import pytest

from src.repositories.gameWindow import creatures as creaturesModule
from src.repositories.gameWindow.creatures import getBestCreature


def _creature(name, slot):
    return {'name': name, 'slot': slot}


@pytest.fixture(autouse=True)
def flatWalkableMap(mocker):
    mocker.patch.object(creaturesModule, 'walkableFloorsSqms', {7: None})
    mocker.patch.object(
        creaturesModule, 'getGameWindowWalkableFloorsSqms',
        return_value=np.ones((11, 15), dtype=np.int8))


def test_empty_list_returns_none():
    assert getBestCreature([], (32000, 32000, 7)) is None


def test_picks_closest_without_priorities():
    near = _creature('wasp', (7, 4))   # Distanz 1 zur Mitte
    far = _creature('rotworm', (7, 2))  # Distanz 3

    best = getBestCreature([far, near], (32000, 32000, 7))

    assert best['name'] == 'wasp'


def test_priority_beats_distance():
    nearLowPrio = _creature('wasp', (7, 4))      # Distanz 1, Prio 1 → 1+16
    farHighPrio = _creature('rotworm', (7, 2))   # Distanz 3, Prio 5 → 3+0

    best = getBestCreature(
        [nearLowPrio, farHighPrio], (32000, 32000, 7),
        {'wasp': 1, 'rotworm': 5})

    assert best['name'] == 'rotworm'


def test_close_priority_still_wins_over_far_high_priority():
    nearLowPrio = _creature('wasp', (7, 4))        # Distanz 1, Prio 4 → 1+4
    farHighPrio = _creature('rotworm', (0, 10))    # weit weg, Prio 5

    best = getBestCreature(
        [farHighPrio, nearLowPrio], (32000, 32000, 7),
        {'wasp': 4, 'rotworm': 5})

    assert best['name'] == 'wasp'


def test_unreachable_creature_is_skipped(mocker):
    walkable = np.ones((11, 15), dtype=np.int8)
    walkable[:, 14] = 0  # Mauer: rechte Spalte unerreichbar
    mocker.patch.object(
        creaturesModule, 'getGameWindowWalkableFloorsSqms',
        return_value=walkable)
    unreachable = _creature('rotworm', (14, 5))
    reachable = _creature('wasp', (7, 4))

    best = getBestCreature(
        [unreachable, reachable], (32000, 32000, 7),
        {'rotworm': 5, 'wasp': 1})

    assert best['name'] == 'wasp'


def test_all_unreachable_returns_none(mocker):
    walkable = np.zeros((11, 15), dtype=np.int8)
    mocker.patch.object(
        creaturesModule, 'getGameWindowWalkableFloorsSqms',
        return_value=walkable)

    best = getBestCreature(
        [_creature('wasp', (7, 4)), _creature('rotworm', (7, 2))],
        (32000, 32000, 7))

    assert best is None


def test_weaker_creature_wins_via_hp_score():
    strong = _creature('wasp', (7, 4))   # Distanz 1, 100% HP → 1+5
    weak = _creature('rotworm', (7, 2))  # Distanz 3, 20% HP → 3+1

    best = getBestCreature(
        [strong, weak], (32000, 32000, 7), {},
        {'wasp': 100, 'rotworm': 20})

    assert best['name'] == 'rotworm'


def test_missing_hp_counts_as_full():
    strong = _creature('wasp', (7, 4))
    weak = _creature('rotworm', (7, 2))

    best = getBestCreature([strong, weak], (32000, 32000, 7), {}, None)

    assert best['name'] == 'wasp'
