"""Todes-Manager: Killer klassifizieren, Leiche bergen, Route fortsetzen.

Ablauf nach dem Tod (hp == 0, erkannt vom Vitals-Waechter):
  1. Killer klassifizieren: Wurde in den letzten KILLER_WINDOW_SECONDS
     ein fremder Spieler (nicht in allies/enemies) gesehen, gilt der Tod
     als PK — der Bot pausiert und hinterlaesst eine Nachricht im
     Ereignis-Log (Dashboard), statt blind weiterzulaufen.
  2. Monster-Tod: kein Pause-Stopp. Der Relogin-Waechter drueckt auf dem
     Todesbildschirm Enter, nach dem Respawn im Tempel geht es erst zum
     Shop (Notfall-Nachkauf, gedeckelt auf EMERGENCY_REFILL_CAP Traenke
     — sonst laeuft die Bergung ohne Heilung und der Char stirbt im
     Loop), dann zum Todespunkt: WalkToCoordinate + Leiche oeffnen (wie
     jede andere Leiche ueber LootCorpseTask). Danach springt der
     Smart-Resume zum naechsten Wegpunkt und die Hunt geht weiter.
  3. Vorrat-Check: Im Bergungs-Event wird der Stand aller
     konfigurierten Item-Regeln (Traenke etc.) festgehalten.

ponytail: EQ-Rueckholung (bag-with-bag, Waffe/Amulet wieder anziehen)
ist bewusst NICHT automatisiert — das Oeffnen der Leiche uebergibt den
Inhalt an die normale Loot-Pipeline; fehlendes EQ erkennt der Bot
visuell nicht zuverlaessig (Upgrade-Trigger: EQ-Slot-Erkennung aus
inventory/images + gezieltes Wieder-Anziehen).
"""
from time import time

from src.gameplay.failsafe import classifyPlayers
from src.gameplay.monitoring import logEvent, saveEventScreenshot
from src.gameplay.smartResume import resumeAtNearestWaypoint
from src.gameplay.supplies import _jumpToLabel, _ruleValue
from src.repositories.actionBar.core import getSlotCount

# Defaults — im Profil (Reiter "Tod") alles ueberschreibbar.
DEFAULT_DEATH_CONFIG = {
    'enabled': True,              # automatische Bergung nach Monster-Tod
    'pauseOnPlayerKill': True,    # bei PK pausieren + Nachricht
    'refillCap': 30,              # Notfall-Nachkauf max. pro Sorte
    'minPotions': 10,             # Mindest-Traenke vor der Bergung
    'killerWindowSeconds': 30,    # Spieler-Sichtung vor Tod = PK
    'refillTimeoutMinutes': 5,    # danach trotzdem bergen
    'recoveryTimeoutMinutes': 10,  # danach Bergung abbrechen
}
# Kompatibilitaet fuer bestehende Tests/Imports.
EMERGENCY_REFILL_CAP = DEFAULT_DEATH_CONFIG['refillCap']


def deathConfig(context):
    """Todes-Config aus dem Profil, fehlende Werte mit Defaults."""
    config = DEFAULT_DEATH_CONFIG.copy()
    stored = context.get('ng_deathConfig') or {}
    for key in config:
        value = stored.get(key)
        if value is not None:
            config[key] = value
    return config


def _nonAllyPlayers(context):
    players = context.get('gameWindow', {}).get('players') or []
    hostile, _friendly, unknown = classifyPlayers(
        players, context.get('allies', []), context.get('enemies', []))
    return hostile + unknown


def watchPlayersSeen(context, now=None):
    """Loop-Hook: merkt sich, wann zuletzt fremde Spieler sichtbar waren."""
    now = time() if now is None else now
    if _nonAllyPlayers(context):
        state = context.setdefault('ng_deathWatch', {})
        state['playersSeenAt'] = now
    return context


def recordDeath(context, now=None):
    """Einmalig beim Tod: Killer und Todespunkt festhalten."""
    now = time() if now is None else now
    if context.get('ng_death'):
        return context
    vitals = context.get('ng_vitals', {})
    coordinate = vitals.get('coordinate') or \
        context.get('ng_radar', {}).get('coordinate')
    valid = (
        coordinate is not None
        and not any(value is None for value in coordinate)
    )
    seenAt = (context.get('ng_deathWatch') or {}).get('playersSeenAt')
    config = deathConfig(context)
    byPlayer = seenAt is not None and \
        now - seenAt <= config['killerWindowSeconds']
    context['ng_death'] = {
        'killer': 'player' if byPlayer else 'monster',
        'coordinate': list(coordinate) if valid else None,
        'at': now,
    }
    kind = 'deathByPlayer' if byPlayer else 'deathByMonster'
    logEvent(kind, {'coordinate': context['ng_death']['coordinate']})
    saveEventScreenshot(context.get('ng_screenshot'), kind)
    autoRecover = config['enabled'] and (
        not byPlayer or not config['pauseOnPlayerKill'])
    if not autoRecover:
        # PK (oder Bergung abgeschaltet): Mensch uebernimmt — die
        # Nachricht liegt im Ereignis-Log.
        context['ng_pause'] = True
    return context


def _suppliesSnapshot(context):
    """Aktueller Stand aller Item-Regeln (Traenke) fuer das Event."""
    snapshot = {}
    supplies = context.get('ng_supplies') or {}
    for rule in supplies.get('rules', []):
        if rule.get('source') != 'item' or rule.get('itemId') is None:
            continue
        try:
            value = _ruleValue(context, rule)
        except Exception:
            value = None
        if value is not None:
            snapshot[str(rule['itemId'])] = value
    return snapshot


def _finishRecovery(context, death, now, looted):
    death['recovered'] = True
    orchestrator = context.get('ng_tasksOrchestrator')
    if orchestrator is not None:
        orchestrator.setRootTask(context, None)
    resumeAtNearestWaypoint(context)
    logEvent('deathRecovered' if looted else 'deathRecoverySkipped', {
        'seconds': int(now - death['at']),
        'supplies': _suppliesSnapshot(context),
    })
    context.pop('ng_death', None)
    return context


def _potionCount(context, potionKey):
    """Anzahl der Traenke im Action-Bar-Slot der Healing-Config."""
    potion = (context.get('healing', {}).get('potions') or {}).get(potionKey)
    if not potion or potion.get('slot') is None:
        return None
    try:
        return getSlotCount(context.get('ng_screenshot'), potion['slot'])
    except Exception:
        return None


def _refillLabel(context):
    """Label des Refill-Abschnitts: Supplies-Regel oder refillChecker."""
    supplies = context.get('ng_supplies') or {}
    for rule in supplies.get('rules', []):
        if rule.get('enabled', True) and rule.get('label'):
            return rule['label']
    items = context.get('ng_cave', {}).get('waypoints', {}).get('items', [])
    for waypoint in items:
        if waypoint.get('type') == 'refillChecker':
            return (waypoint.get('options') or {}).get(
                'waypointLabelToRedirect')
    return None


def _handleRefill(context, death, now, config):
    """Notfall-Nachkauf nach dem Tod: wenige Traenke, dann Bergung."""
    minPotions = config['minPotions']
    health = _potionCount(context, 'firstHealthPotion')
    mana = _potionCount(context, 'firstManaPotion')
    if not death.get('refillStarted'):
        enough = (
            (health is None or health >= minPotions)
            and (mana is None or mana >= minPotions)
        )
        label = None if enough else _refillLabel(context)
        if enough or not label:
            death['refillDone'] = True
            return context
        death['refillStarted'] = True
        death['refillAt'] = now
        death['refillCap'] = config['refillCap']
        _jumpToLabel(context, label)
        logEvent('deathRefillStarted', {
            'label': label, 'cap': config['refillCap'],
        })
        return context
    enough = (
        (health is None or health >= minPotions)
        and (mana is None or mana >= minPotions)
    )
    if enough:
        death['refillDone'] = True
        death.pop('refillCap', None)
        logEvent('deathRefillDone', {'health': health, 'mana': mana})
        return context
    if now - death.get('refillAt', now) > config['refillTimeoutMinutes'] * 60:
        death['refillDone'] = True
        death.pop('refillCap', None)
        logEvent('deathRefillFailed', {'health': health, 'mana': mana})
    return context


def watchDeathRecovery(context, now=None):
    """Loop-Hook: nach Monster-Tod Leiche bergen und Route fortsetzen."""
    death = context.get('ng_death')
    if not death:
        return context
    now = time() if now is None else now
    config = deathConfig(context)
    waitsForHuman = (
        (death['killer'] == 'player' and config['pauseOnPlayerKill'])
        or not config['enabled']
    )
    if waitsForHuman:
        if context.get('ng_pause'):
            return context  # wartet auf den Menschen
        # Mensch hat selbst weitergemacht.
        logEvent('deathAcknowledged', {})
        return _finishRecovery(context, death, now, looted=False)
    coordinate = context.get('ng_radar', {}).get('coordinate')
    if coordinate is None or any(value is None for value in coordinate):
        return context  # Todesbildschirm — Relogin-Waechter drueckt Enter
    hp = context.get('ng_statusBar', {}).get('hpPercentage')
    if not hp:
        return context  # noch tot bzw. Lebensanzeige nicht lesbar
    if now - death['at'] > config['recoveryTimeoutMinutes'] * 60:
        logEvent('deathRecoveryFailed', {'reason': 'timeout'})
        return _finishRecovery(context, death, now, looted=False)
    if not death.get('refillDone'):
        context = _handleRefill(context, death, now, config)
        if not death.get('refillDone'):
            return context  # Shop-Tour laeuft noch
    if not death.get('coordinate'):
        return _finishRecovery(context, death, now, looted=False)
    orchestrator = context['ng_tasksOrchestrator']
    if not death.get('recoveryStarted'):
        from src.gameplay.core.tasks.lootCorpse import LootCorpseTask
        death['recoveryStarted'] = True
        corpse = {'name': 'own corpse', 'coordinate': death['coordinate']}
        orchestrator.setRootTask(context, LootCorpseTask(corpse))
        logEvent('deathRecoveryStarted', {
            'coordinate': death['coordinate'],
        })
        return context
    root = orchestrator.rootTask
    if root is None or root.status == 'completed':
        return _finishRecovery(context, death, now, looted=True)
    return context
