"""Failsafe: menschliche Reaktion bei Spielern auf dem Bildschirm.

Drei Klassen von Spielern:
  - Feinde (Namen in context['enemies']): sofort Eskalation.
  - Verbuendete (Namen in context['allies']): werden ignoriert.
  - Unbekannte: Eskalation nach triggerSeconds Sichtdauer (Report-Schutz).

Eskalation heisst NICHT mehr nur stehen bleiben (Freifach fuer PKs):
  - Kein Kampfsign (kein eigenes Ziel): sofort ausloggen (Ctrl+Q).
  - Im Kampf (Battle-Zeichen blockiert Logout): Ziel loesen (ESC), in die
    Safe-Zone laufen (Label safe/pz/depot/dp/depositer/temple) und den
    Logout alle 5s erneut versuchen, bis das Zeichen verfaellt. Erst
    nach 12 Fehlversuchen wird pausiert — eingeloggt offline im Feld
    ist schlimmer als pausiert online.

Config per Env:
  TIBIAPILOT_FAILSAFE=0          -> aus
  TIBIAPILOT_FAILSAFE_SECONDS    -> Sichtdauer bis zum Ausloesen (Default 2.5)
"""
import os
import time

from src.gameplay.monitoring import logEvent, saveEventScreenshot
from src.utils.keyboard import hotkey, press

FAILSAFE_ENV = 'TIBIAPILOT_FAILSAFE'
TRIGGER_SECONDS_ENV = 'TIBIAPILOT_FAILSAFE_SECONDS'

SAFE_LABELS = ('safe', 'pz', 'depot', 'dp', 'depositer', 'temple')
LOGOUT_RETRY_SECONDS = 5
LOGOUT_MAX_ATTEMPTS = 12


def classifyPlayers(players, allies, enemies):
    """Teilt sichtbare Spieler in feindlich / verbuendet / unbekannt."""
    allyNames = {name.lower() for name in allies}
    enemyNames = {name.lower() for name in enemies}
    hostile, friendly, unknown = [], [], []
    for player in players:
        name = (player.get('name') or '').lower()
        if name in enemyNames:
            hostile.append(player)
        elif name in allyNames:
            friendly.append(player)
        else:
            unknown.append(player)
    return hostile, friendly, unknown


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


class PlayerFailsafe:
    def __init__(self):
        self.enabled = os.getenv(FAILSAFE_ENV, '1') != '0'
        self.triggerSeconds = float(os.getenv(TRIGGER_SECONDS_ENV, '2.5'))
        self.firstSeenAt = None

    def _escalate(self, context, now, reason, players):
        orchestrator = context.get('ng_tasksOrchestrator')
        if (orchestrator is not None and
                orchestrator.getCurrentTask(context) is not None):
            orchestrator.setRootTask(context, None)
        context['ng_failsafe'] = {
            'reason': reason, 'count': len(players), 'at': now,
        }
        logEvent('failsafe', context['ng_failsafe'])
        saveEventScreenshot(context.get('ng_screenshot'), reason)
        self.firstSeenAt = None
        inCombat = context.get('ng_cave', {}).get('isAttackingSomeCreature')
        if not inCombat:
            # Kein Kampfsign — Logout geht sofort.
            hotkey('ctrl', 'q')
            context['ng_pause'] = True
            return context
        # Kampfsign aktiv: loesen, in Sicherheit laufen, spaeter ausloggen.
        press('esc')
        _jumpToSafeLabel(context)
        context['ng_logoutRetry'] = {
            'attempts': 0, 'nextAt': now, 'reason': reason,
        }
        return context

    def _logoutRetryTick(self, context, now):
        retry = context.get('ng_logoutRetry')
        if retry is None:
            return None
        coordinate = context.get('ng_radar', {}).get('coordinate')
        if coordinate is None and retry['attempts'] > 0:
            context.pop('ng_logoutRetry', None)
            context['ng_pause'] = True
            logEvent('loggedOut', {'reason': retry['reason']})
            return context
        if context.get('ng_cave', {}).get('isAttackingSomeCreature'):
            press('esc')
        if now < retry['nextAt']:
            return context
        hotkey('ctrl', 'q')
        retry['attempts'] += 1
        retry['nextAt'] = now + LOGOUT_RETRY_SECONDS
        if retry['attempts'] >= LOGOUT_MAX_ATTEMPTS:
            context.pop('ng_logoutRetry', None)
            context['ng_pause'] = True
            logEvent('logoutFailed', {'reason': retry['reason']})
        return context

    def tick(self, context, now=None):
        if not self.enabled:
            return context
        now = time.time() if now is None else now
        retried = self._logoutRetryTick(context, now)
        if retried is not None:
            return retried
        players = context.get('gameWindow', {}).get('players') or []
        if context.get('ng_pause') or not players:
            self.firstSeenAt = None
            return context

        hostile, _friendly, unknown = classifyPlayers(
            players, context.get('allies', []), context.get('enemies', []))
        if hostile:
            # Feinde brauchen keine Sichtdauer — sofort reagieren.
            return self._escalate(context, now, 'enemy', hostile)
        if not unknown:
            self.firstSeenAt = None
            return context

        if self.firstSeenAt is None:
            self.firstSeenAt = now
            return context
        if now - self.firstSeenAt < self.triggerSeconds:
            return context
        return self._escalate(context, now, 'players', unknown)
