"""Globaler Vorrats-Waechter: bei niedrigem Bestand zum Refill-Label.

Prueft im Loop regelmaessig konfigurierte Regeln (Trank-Anzahl, Cap,
Stamina) und springt bei Unterschreiten direkt zum Ziel-Label — im
Gegensatz zum klassischen refillChecker-Wegpunkt ueberall in der Route,
nicht nur an einem Pruefpunkt. Das Kaufen selbst uebernehmen die
bestehenden Buy-/Withdraw-Wegpunkte der Route.

Hysterese: Eine ausgeloeste Regel ist entschaerft, bis der Wert die
Schwelle wieder erreicht (sonst wuerde der Waechter waehrend der
kompletten Refill-Tour gegen die Route kaempfen).

Notfall-Stufe: Bleibt der Bestand 8 Minuten nach dem Refill-Sprung
unter der Schwelle (kein Gold, NPC blockiert, Script kaputt), geht es
in die Safe-Zone (depot/dp/depositer/temple/safe/pz) und der Bot
pausiert mit Event — leer weiter hunten ist die schlechtere Option.
"""
from time import time

from src.gameplay.monitoring import logEvent
from src.repositories.actionBar.core import getSlotCount
from src.repositories.skills.core import getCapacity, getStamina

CHECK_INTERVAL_SECONDS = 5
REFILL_TIMEOUT_SECONDS = 480
_SAFE_LABELS = ('depot', 'dp', 'depositer', 'temple', 'safe', 'pz')

_OPERATORS = {
    '<': lambda value, target: value < target,
    '<=': lambda value, target: value <= target,
    '>': lambda value, target: value > target,
    '>=': lambda value, target: value >= target,
    '==': lambda value, target: value == target,
}


def _itemSlot(context, itemId):
    slots = context.get('ng_actionBar', {}).get('slots', {})
    slot = slots.get(str(itemId))
    if slot is not None:
        return slot
    return context.get('ng_bbot', {}).get('itemSlots', {}).get(str(itemId))


def _ruleValue(context, rule):
    source = rule.get('source')
    if source == 'capacity':
        return getCapacity(context['ng_screenshot'])
    if source == 'stamina':
        return getStamina(context['ng_screenshot'])
    if source == 'item':
        slot = _itemSlot(context, rule.get('itemId'))
        if slot is None:
            return None
        return getSlotCount(context['ng_screenshot'], slot)
    return None


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


def _emergency(context, rule, value, now):
    """Refill gescheitert (kein Gold/NPC/Script-Fehler): Safe-Zone+Pause."""
    items = context['ng_cave']['waypoints']['items']
    target = next(
        (index for index, waypoint in enumerate(items)
         if (waypoint.get('label') or '').lower() in _SAFE_LABELS),
        None,
    )
    if target is not None:
        context['ng_cave']['waypoints']['currentIndex'] = target
        context['ng_cave']['waypoints']['state'] = None
    context['ng_pause'] = True
    logEvent('suppliesEmergency', {
        'source': rule.get('source'), 'itemId': rule.get('itemId'),
        'value': value, 'target': rule.get('target'),
        'safeLabelFound': target is not None,
    })
    rule['emergencyAt'] = now


def watchSupplies(context):
    """Loop-Hook: loest Refill-Spruenge bei niedrigem Bestand aus."""
    supplies = context.get('ng_supplies')
    if not supplies or not supplies.get('enabled'):
        return context
    now = time()
    if now - supplies.get('lastCheckAt', 0) < CHECK_INTERVAL_SECONDS:
        return context
    supplies['lastCheckAt'] = now
    for rule in supplies.get('rules', []):
        if not rule.get('enabled'):
            continue
        value = _ruleValue(context, rule)
        if value is None:
            continue
        triggered = _OPERATORS[rule.get('operator', '<')](
            value, rule.get('target', 0))
        if not triggered:
            rule['armed'] = True
            rule['missingLogged'] = False
            rule.pop('triggeredAt', None)
            rule.pop('emergencyAt', None)
            continue
        if not rule.get('armed', True):
            if (rule.get('triggeredAt') is not None
                    and rule.get('emergencyAt') is None
                    and now - rule['triggeredAt'] > REFILL_TIMEOUT_SECONDS):
                _emergency(context, rule, value, now)
            continue
        label = rule.get('label', '')
        if _jumpToLabel(context, label):
            rule['armed'] = False
            rule['triggeredAt'] = now
            logEvent('suppliesRefill', {
                'source': rule.get('source'), 'itemId': rule.get('itemId'),
                'value': value, 'target': rule.get('target'),
                'label': label,
            })
        elif not rule.get('missingLogged'):
            rule['missingLogged'] = True
            logEvent('suppliesLabelMissing', {'label': label})
    return context
