from src.utils.humanize import pause
from src.gameplay.typings import Context
from src.repositories.inventory.core import images
from src.shared.typings import GrayImage
from src.utils.core import locate
from src.utils.mouse import drag, useClick
from ...typings import Context
from .common.base import BaseTask


# Rasterabstand der Felder in einem Container (32 Pixel Feld + 5 Pixel
# Abstand) und Anzahl Spalten. Das erste Feld liegt bei Titelleiste
# plus (10, 18).
FELD = 32
ABSTAND = 37
SPALTEN = 4
ZEILEN = 5

# Items, die NICHT eingelagert werden. Sie werden im naechsten Zug
# gebraucht - ohne Seil und Schaufel kommt der Charakter nicht durch die
# Hoehle, ohne Traenke nicht durch den Kampf. Leere Flaschen gehoeren
# ebenfalls nicht ins Depot; die wirft der Bot unterwegs weg.
#
# Namen beziehen sich auf images['slots']; fehlt eine Vorlage, wird der
# Eintrag stillschweigend uebersprungen - dann kann dieses Item eben noch
# nicht geschuetzt werden.
BEHALTEN = (
    'rope', 'shovel',
    'big empty potion flask',
    'medium empty potion flask',
    'small empty potion flask',
)


def _behaltenVorlagen():
    return [images['slots'][name] for name in BEHALTEN
            if name in images['slots']]


# TODO: check if item was moved on did. Is possible to check it by cap
class DragItemsTask(BaseTask):
    """Leert einen Container Feld fuer Feld in einen Zielcontainer.

    Es wird immer nur ein einzelnes Item bewegt, nie ein ganzer
    Rucksack. Felder mit Dingen aus BEHALTEN werden uebersprungen -
    frueher wanderte auch Seil, Schaufel und der Manatrank ins Depot,
    womit der naechste Zug nicht mehr moeglich war.
    """

    def __init__(self, containerBarImage: GrayImage, targetContainerImage: GrayImage):
        super().__init__()
        self.name = 'dragItems'
        self.terminable = False
        self.containerBarImage = containerBarImage
        self.targetContainerImage = targetContainerImage

    def _feldBild(self, screenshot, barPosition, index: int):
        spalte, zeile = index % SPALTEN, index // SPALTEN
        x = barPosition[0] + 10 + spalte * ABSTAND
        y = barPosition[1] + 18 + zeile * ABSTAND
        return screenshot[y:y + FELD, x:x + FELD], (x, y)

    def _istGeschuetzt(self, feldBild) -> bool:
        return any(locate(feldBild, vorlage, confidence=0.8) is not None
                   for vorlage in _behaltenVorlagen())

    def _naechstesFeld(self, screenshot, barPosition):
        """Erstes Feld, das eingelagert werden darf - oder None."""
        for index in range(SPALTEN * ZEILEN):
            feldBild, (x, y) = self._feldBild(screenshot, barPosition, index)
            if feldBild.shape[0] < FELD or feldBild.shape[1] < FELD:
                continue
            if locate(feldBild, images['slots']['empty']) is not None:
                continue
            if self._istGeschuetzt(feldBild):
                continue
            return feldBild, (x + 2, y + 2)
        return None, None

    # TODO: add unit tests
    def do(self, context: Context) -> Context:
        containerBarPosition = locate(
            context['ng_screenshot'], self.containerBarImage, confidence=0.8)
        if containerBarPosition is None:
            self.terminable = True
            return context

        feldBild, quelle = self._naechstesFeld(
            context['ng_screenshot'], containerBarPosition)
        if feldBild is None:
            # Nur noch leere oder geschuetzte Felder - fertig.
            self.terminable = True
            return context

        # Ein verschachtelter Rucksack wird geoeffnet, nicht verschoben:
        # seine Items sollen ebenfalls einzeln ins Depot wandern.
        lootName = (context.get('ng_backpacks') or {}).get('loot')
        lootVorlage = images['slots'].get(lootName) if lootName else None
        if lootVorlage is not None and locate(
                feldBild, lootVorlage, confidence=0.8) is not None:
            useClick(quelle)
            return context

        zielPosition = locate(
            context['ng_screenshot'], self.targetContainerImage, confidence=0.8)
        if zielPosition is None:
            self.terminable = True
            return context
        drag(quelle, (zielPosition[0] + 2, zielPosition[1] + 2))
        pause(0.4)
        return context
