"""Runtime-Tasks fuer BBot-Makro-Schritte, Delay- und Sell-Wegpunkte.

Der Importer zerlegt Makros in Einzelschritte (useItemOn/useMap/pickup/
say/wait/move/equipHelmet/pause); BBotMacroTask fuehrt sie als VectorTask
sequentiell aus. Koordinaten None bedeuten "aktuelle Position" (BBot
!X!/!Y!/!Z!) und werden auf die Wegpunkt-Koordinate aufgeloest.
"""
from src.gameplay.monitoring import logEvent
from src.repositories.actionBar.slotIcons import getItemIcon
from src.repositories.gameWindow.core import getSlotFromCoordinate
from src.repositories.gameWindow.slot import clickSlot, getSlotPosition
from src.repositories.inventory.core import images as inventoryImages
from src.utils.core import locate
from src.utils.keyboard import press
from src.utils.mouse import drag, rightClick
from ...typings import Context
from .bbot import BBotSayTask
from .common.base import BaseTask
from .common.vector import VectorTask
from .rightClickUse import RightClickUseTask
from .setNextWaypoint import SetNextWaypointTask

_DIRECTION_KEYS = {'N': 'up', 'E': 'right', 'S': 'down', 'W': 'left'}


def _backpackItemPosition(screenshot, backpackName, itemId):
    """Findet ein Item-Icon im Haupt-Rucksack; Mitte oder None."""
    icon = getItemIcon(itemId)
    container = inventoryImages['containersBars'].get(backpackName)
    if icon is None or container is None:
        return None
    bar = locate(screenshot, container, confidence=0.8)
    if bar is None:
        return None
    x0, y0 = bar[0], bar[1] + 18
    region = screenshot[y0:, x0:x0 + 176]
    position = locate(region, icon, confidence=0.75)
    if position is None:
        return None
    return (x0 + position[0] + 16, y0 + position[1] + 16)


class WaitTask(BaseTask):
    def __init__(self, seconds):
        super().__init__()
        self.name = 'wait'
        self.delayAfterComplete = max(0.1, seconds)

    def do(self, context: Context) -> Context:
        return context


class UseBackpackItemOnTask(BaseTask):
    """Benutzt ein Item aus dem Rucksack (Rechtsklick) auf eine SQM."""

    def __init__(self, itemId, coordinate=None):
        super().__init__()
        self.name = 'useBackpackItemOn'
        self.delayAfterComplete = 0.5
        self.itemId = itemId
        self.coordinate = coordinate

    def do(self, context: Context) -> Context:
        position = _backpackItemPosition(
            context['ng_screenshot'],
            context['ng_backpacks'].get('main'), self.itemId)
        if position is None:
            logEvent('macroItemMissing', {'itemId': self.itemId})
            return context
        rightClick(position)
        target = self.coordinate or context['ng_radar']['coordinate']
        slot = getSlotFromCoordinate(context['ng_radar']['coordinate'], target)
        if slot is not None:
            clickSlot(slot, context['gameWindow']['coordinate'])
        return context


class EquipBackpackItemTask(BaseTask):
    """Rueckt ein Ausruestungsstueck aus dem Rucksack an (Rechtsklick)."""

    def __init__(self, itemId):
        super().__init__()
        self.name = 'equipBackpackItem'
        self.delayAfterComplete = 0.5
        self.itemId = itemId

    def do(self, context: Context) -> Context:
        position = _backpackItemPosition(
            context['ng_screenshot'],
            context['ng_backpacks'].get('main'), self.itemId)
        if position is None:
            logEvent('macroItemMissing', {'itemId': self.itemId})
            return context
        rightClick(position)
        return context


class PickupFromGroundTask(BaseTask):
    """Hebt ein Item vom Boden auf (Drag von SQM in den Rucksack)."""

    def __init__(self, coordinate=None):
        super().__init__()
        self.name = 'pickupFromGround'
        self.delayAfterComplete = 0.5
        self.coordinate = coordinate

    def do(self, context: Context) -> Context:
        target = self.coordinate or context['ng_radar']['coordinate']
        slot = getSlotFromCoordinate(context['ng_radar']['coordinate'], target)
        container = inventoryImages['containersBars'].get(
            context['ng_backpacks'].get('main'))
        if slot is None or container is None:
            return context
        bar = locate(context['ng_screenshot'], container, confidence=0.8)
        if bar is None:
            return context
        source = getSlotPosition(slot, context['gameWindow']['coordinate'])
        drag(source, (bar[0] + 16, bar[1] + 34))
        return context


class MoveKeyTask(BaseTask):
    def __init__(self, direction):
        super().__init__()
        self.name = 'moveKey'
        self.direction = direction

    def do(self, context: Context) -> Context:
        press(_DIRECTION_KEYS.get(self.direction, 'down'))
        return context


class TurnKeyTask(BaseTask):
    """Dreht den Charakter ohne Bewegung (Ctrl+Pfeil)."""

    def __init__(self, direction):
        super().__init__()
        self.name = 'turnKey'
        self.direction = direction

    def do(self, context: Context) -> Context:
        from src.utils.keyboard import hotkey
        hotkey('ctrl', _DIRECTION_KEYS.get(self.direction, 'down'))
        return context


class LogoutTask_(BaseTask):
    def __init__(self):
        super().__init__()
        self.name = 'bbotLogout'

    def do(self, context: Context) -> Context:
        from src.utils.keyboard import hotkey
        hotkey('ctrl', 'q')
        return context


class CloseClientTask(BaseTask):
    """Schliesst den Tibia-Client komplett (BBot Tibia.Close())."""

    def __init__(self):
        super().__init__()
        self.name = 'closeClient'

    def do(self, context: Context) -> Context:
        from src.utils.keyboard import hotkey
        hotkey('alt', 'f4')
        return context


class PauseTask(BaseTask):
    def __init__(self):
        super().__init__()
        self.name = 'pauseBot'

    def do(self, context: Context) -> Context:
        context['ng_pause'] = True
        return context


class BBotMacroTask(VectorTask):
    """Fuehrt die Steps eines importierten BBot-Makros sequentiell aus."""

    def __init__(self, waypoint):
        super().__init__()
        self.name = 'bbotMacro'
        self.isRootTask = True
        self.waypoint = waypoint

    def onBeforeStart(self, context: Context) -> Context:
        tasks = []
        for step in self.waypoint['options'].get('steps', []):
            coordinate = step.get('coordinate') or self.waypoint['coordinate']
            action = step.get('action')
            task = None
            if action == 'useMap':
                task = RightClickUseTask({
                    'coordinate': coordinate, 'label': '', 'ignore': False,
                    'options': {},
                })
            elif action == 'useItemOn':
                task = UseBackpackItemOnTask(step['itemId'], coordinate)
            elif action == 'pickup':
                task = PickupFromGroundTask(coordinate)
            elif action == 'say':
                task = BBotSayTask({
                    'coordinate': coordinate, 'label': '', 'ignore': False,
                    'options': {'text': step['text']},
                })
            elif action == 'wait':
                task = WaitTask(step['ms'] / 1000)
            elif action == 'pause':
                task = PauseTask()
            elif action == 'move':
                task = MoveKeyTask(step['direction'])
            elif action == 'equipHelmet':
                task = EquipBackpackItemTask(step['itemId'])
            elif action == 'turn':
                task = TurnKeyTask(step['direction'])
            elif action == 'logout':
                task = LogoutTask_()
            elif action == 'closeClient':
                task = CloseClientTask()
            elif action == 'unequipHelmet':
                # ponytail: Helm-Slot-Position ist clientabhaengig und
                # nicht vermessen — Schritt wird protokolliert statt
                # blind geklickt (Upgrade-Trigger: Equipment-Panel
                # vermessen, dann Drag vom Helm-Slot in den Rucksack).
                logEvent('macroStepUnsupported', {'step': 'unequipHelmet'})
            if task is not None:
                task.setParentTask(self).setRootTask(self)
                tasks.append(task)
        tasks.append(SetNextWaypointTask().setParentTask(self).setRootTask(self))
        self.tasks = tasks
        return context


class BBotDelayTask(VectorTask):
    """Delay-Wegpunkt: wartet die angegebenen Sekunden."""

    def __init__(self, waypoint):
        super().__init__()
        self.name = 'bbotDelay'
        self.isRootTask = True
        self.waypoint = waypoint

    def onBeforeStart(self, context: Context) -> Context:
        self.tasks = [
            WaitTask(self.waypoint['options'].get('seconds', 1)).setParentTask(self).setRootTask(self),
            SetNextWaypointTask().setParentTask(self).setRootTask(self),
        ]
        return context
