import numpy as np
import pytest

from src.gameplay.core.tasks import dragItems as modul
from src.gameplay.core.tasks.dragItems import DragItemsTask


BAR = np.zeros((12, 57), dtype=np.uint8)
ZIEL = np.zeros((21, 32), dtype=np.uint8)


def _task():
    return DragItemsTask(BAR, ZIEL)


def _context():
    return {
        'ng_screenshot': np.zeros((1080, 1920), dtype=np.uint8),
        'ng_backpacks': {'main': 'Backpack', 'loot': 'Backpack'},
    }


def test_ends_when_container_bar_is_gone(mocker):
    """Ohne sichtbaren Container gibt es nichts zu tun."""
    mocker.patch.object(modul, 'locate', return_value=None)
    task = _task()

    task.do(_context())

    assert task.terminable is True


def test_ends_when_only_protected_items_remain(mocker):
    """Sind nur noch geschuetzte Felder da, ist das Einlagern fertig."""
    task = _task()
    mocker.patch.object(task, '_naechstesFeld', return_value=(None, None))
    mocker.patch.object(modul, 'locate', return_value=(10, 20, 57, 12))
    zieh = mocker.patch.object(modul, 'drag')

    task.do(_context())

    assert task.terminable is True
    zieh.assert_not_called()


def test_moves_a_single_item(mocker):
    """Es wird genau EIN Feld bewegt - nie ein ganzer Rucksack."""
    task = _task()
    feld = np.zeros((32, 32), dtype=np.uint8)
    mocker.patch.object(task, '_naechstesFeld', return_value=(feld, (100, 200)))
    mocker.patch.object(modul, 'locate', side_effect=[
        (10, 20, 57, 12),   # Container-Titelleiste
        None,               # kein verschachtelter Rucksack im Feld
        (500, 600, 32, 21),  # Zielcontainer
    ])
    zieh = mocker.patch.object(modul, 'drag')
    mocker.patch.object(modul, 'pause')

    task.do(_context())

    assert task.terminable is False
    zieh.assert_called_once_with((100, 200), (502, 602))


def test_protected_items_are_skipped(mocker):
    """Seil und Schaufel bleiben liegen, das naechste Feld wird genommen."""
    task = _task()
    screenshot = np.zeros((1080, 1920), dtype=np.uint8)
    bar = (100, 100, 57, 12)

    # Feld 0 gilt als geschuetzt, Feld 1 als normal belegt.
    def istGeschuetzt(feldBild):
        return istGeschuetzt.aufrufe.append(None) or len(istGeschuetzt.aufrufe) == 1
    istGeschuetzt.aufrufe = []
    mocker.patch.object(task, '_istGeschuetzt', side_effect=istGeschuetzt)
    mocker.patch.object(modul, 'locate', return_value=None)  # nie "leer"

    _, quelle = task._naechstesFeld(screenshot, bar)

    # Erstes Feld liegt bei bar+(10,18), das zweite 37 Pixel weiter rechts.
    assert quelle == (100 + 10 + 37 + 2, 100 + 18 + 2)


def test_keep_list_only_uses_existing_templates():
    """Fehlende Vorlagen duerfen die Schutzliste nicht sprengen."""
    vorlagen = modul._behaltenVorlagen()

    assert isinstance(vorlagen, list)
    assert len(vorlagen) <= len(modul.BEHALTEN)
