from src.gameplay.core.tasks.buyItem import BuyItemTask
from src.gameplay.core.tasks.common.base import BaseTask
from src.gameplay.core.tasks.common.vector import VectorTask
from src.gameplay.core.tasks.enableChat import EnableChatTask
from src.gameplay.core.tasks.closeContainer import CloseContainerTask
from src.gameplay.core.tasks.expandBackpack import ExpandBackpackTask
from src.gameplay.core.tasks.openBackpack import OpenBackpackTask
from src.gameplay.core.tasks.say import SayTask
from src.gameplay.core.tasks.scrollToItem import ScrollToItemTask
from src.gameplay.core.tasks.selectChatTab import SelectChatTabTask
from src.gameplay.core.tasks.setChatOff import SetChatOffTask
from src.gameplay.core.tasks.setNextWaypoint import SetNextWaypointTask
from src.repositories.actionBar.core import getSlotCount
from src.repositories.inventory.core import images
from src.repositories.skills.core import getCapacity, getStamina
from src.utils.array import getNextArrayIndex
from src.utils.keyboard import hotkey


class BBotActionTask(BaseTask):
    def __init__(self, waypoint):
        super().__init__()
        self.name = 'bbotAction'
        self.isRootTask = True
        self.waypoint = waypoint
        self.matched = False

    def do(self, context):
        options = self.waypoint['options']
        if options.get('action') == 'condition':
            self.matched = any(_check(context, check) for check in options.get('checks', []))
        return context

    def onComplete(self, context):
        options = self.waypoint['options']
        if options.get('action') == 'goLabel':
            return _jump(context, options.get('label', ''))
        if options.get('action') != 'condition':
            return _next(context)
        if self.matched and options.get('trueAction') == 'logout':
            hotkey('ctrl', 'q')
            context['ng_pause'] = True
            return context
        label = options.get('trueLabel') if self.matched else options.get('falseLabel')
        if label is None:
            return _next(context)
        if label == '':
            context['ng_cave']['waypoints']['currentIndex'] = 0
            context['ng_cave']['waypoints']['state'] = None
            return context
        return _jump(context, label)


class BBotSayTask(VectorTask):
    def __init__(self, waypoint):
        super().__init__()
        self.name = 'bbotSay'
        self.isRootTask = True
        self.text = waypoint['options']['text']

    def onBeforeStart(self, context):
        self.tasks = _say(self, self.text) + [
            SetNextWaypointTask().setParentTask(self).setRootTask(self),
        ]
        return context


class BBotWithdrawTask(VectorTask):
    def __init__(self, waypoint):
        super().__init__()
        self.name = 'bbotWithdraw'
        self.isRootTask = True
        self.items = waypoint['options']['items']

    def onBeforeStart(self, context):
        total = 0
        slots = context.get('ng_bbot', {}).get('itemSlots', {})
        for item in self.items:
            slot = slots.get(str(item['id']))
            count = getSlotCount(context['ng_screenshot'], slot) if slot is not None else None
            if count is not None:
                total += max(0, item['target'] - count) * item['unitPrice']
        self.tasks = (_say(self, str(total)) if total > 0 else []) + [
            SetNextWaypointTask().setParentTask(self).setRootTask(self),
        ]
        return context


class BBotBuyTask(VectorTask):
    def __init__(self, waypoint):
        super().__init__()
        self.name = 'bbotBuy'
        self.isRootTask = True
        self.item_id = waypoint['options']['id']
        self.item = waypoint['options']['item']
        self.target = waypoint['options']['target']

    def onBeforeStart(self, context):
        slot = context.get('ng_bbot', {}).get('itemSlots', {}).get(str(self.item_id))
        count = getSlotCount(context['ng_screenshot'], slot) if slot is not None else None
        amount = max(0, self.target - count) if count is not None else 0
        self.tasks = [
            BuyItemTask(self.item, amount).setParentTask(self).setRootTask(self),
            SetNextWaypointTask().setParentTask(self).setRootTask(self),
        ]
        return context


class BBotSellTask(BaseTask):
    def __init__(self, waypoint):
        super().__init__()
        self.name = 'bbotSell'
        self.isRootTask = True
        self.delayBeforeStart = 1
        self.delayAfterComplete = 1
        self.item = waypoint['options']['item']

    def do(self, context):
        import src.repositories.refill.core as refillCore
        if not refillCore.sellItem(context['ng_screenshot'], self.item):
            self.status = 'notStarted'
            self.startedAt = None
        return context

    def onComplete(self, context):
        return _next(context)


class BBotResetBackpacksTask(VectorTask):
    def __init__(self):
        super().__init__()
        self.name = 'bbotResetBackpacks'
        self.isRootTask = True

    def onBeforeStart(self, context):
        main = context['ng_backpacks'].get('main')
        loot = context['ng_backpacks'].get('loot')
        main_bar = images['containersBars'].get(main)
        loot_bar = images['containersBars'].get(loot)
        loot_slot = images['slots'].get(loot)
        if any(value is None for value in (main, loot, main_bar, loot_bar, loot_slot)):
            self.tasks = [SetNextWaypointTask().setParentTask(self).setRootTask(self)]
            return context
        self.tasks = [
            CloseContainerTask(loot_bar).setParentTask(self).setRootTask(self),
            CloseContainerTask(main_bar).setParentTask(self).setRootTask(self),
            OpenBackpackTask(main).setParentTask(self).setRootTask(self),
            ExpandBackpackTask(main).setParentTask(self).setRootTask(self),
            ScrollToItemTask(main_bar, loot_slot).setParentTask(self).setRootTask(self),
            OpenBackpackTask(loot).setParentTask(self).setRootTask(self),
            SetNextWaypointTask().setParentTask(self).setRootTask(self),
        ]
        return context


def _say(parent, text):
    return [
        SelectChatTabTask('local chat').setParentTask(parent).setRootTask(parent),
        EnableChatTask().setParentTask(parent).setRootTask(parent),
        SayTask(text).setParentTask(parent).setRootTask(parent),
        SetChatOffTask().setParentTask(parent).setRootTask(parent),
    ]


def _check(context, check):
    source = check['source']
    if source == 'capacity':
        value = getCapacity(context['ng_screenshot'])
    elif source == 'stamina':
        value = getStamina(context['ng_screenshot'])
    elif source == 'creatures':
        value = len(context['gameWindow']['monsters'])
    elif source == 'item':
        slot = context.get('ng_bbot', {}).get('itemSlots', {}).get(str(check['value']))
        value = getSlotCount(context['ng_screenshot'], slot) if slot is not None else None
    else:
        value = check['value']
    if value is None:
        return False
    target = check['target']
    return {
        '<': value < target,
        '<=': value <= target,
        '>': value > target,
        '>=': value >= target,
        '==': value == target,
    }[check['operator']]


def _next(context):
    waypoints = context['ng_cave']['waypoints']
    waypoints['currentIndex'] = getNextArrayIndex(waypoints['items'], waypoints['currentIndex'])
    waypoints['state'] = None
    return context


def _jump(context, label):
    items = context['ng_cave']['waypoints']['items']
    target = next(
        (index for index, waypoint in enumerate(items) if waypoint['label'].lower() == label.lower()),
        None,
    )
    if target is None:
        return _next(context)
    context['ng_cave']['waypoints']['currentIndex'] = target
    context['ng_cave']['waypoints']['state'] = None
    return context
