"""Generischer Disconnect-Re-Login.

Landet der Charakter ungewollt auf dem Login-/Char-Select-Screen
(Server-Save, Kick, Verbindungsabbruch), gibt es keine Radar-Koordinate.
Laesst die Koordinate laenger als 30s aus, drueckt der Bot periodisch
Enter, bis er wieder im Spiel ist, und setzt die Route am Start-Label
fort. Session-Phasen (logout/offline/relogin) gehoeren dem
Session-Rhythmus und werden nicht doppelt gesteuert; manuelle Pausen
ebenfalls respektiert.

ponytail: Bei Radar-Fehlern (Minimap zu) waere Enter im Spiel ein
Chat-Open/Close pro Versuch — unschaedlich (Upgrade-Trigger:
Login-Screen-Bild erkennen statt Koordinaten-Proxy).
"""
from time import monotonic

from src.gameplay.monitoring import logEvent
from src.gameplay.smartResume import resumeAtNearestWaypoint
from src.utils.keyboard import press

RELOGIN_AFTER_SECONDS = 30
RELOGIN_RETRY_SECONDS = 20
# Bewusst niedrig: Tibia sperrt die IP-Adresse nach wenigen fehlgeschlagenen
# Anmeldeversuchen fuer 30 Minuten. Lieber frueh pausieren und den Nutzer
# schauen lassen, als sich in eine Sperre zu rennen.
RELOGIN_MAX_ATTEMPTS = 3

_SESSION_OWNED_STATES = ('logout', 'offline', 'relogin')


def watchRelogin(context):
    """Loop-Hook im Koordinaten-los-Zweig: loggt nach Kick wieder ein."""
    if context['ng_pause']:
        return context
    sessionState = (context.get('ng_session') or {}).get('state')
    if sessionState in _SESSION_OWNED_STATES:
        return context
    coordinate = context['ng_radar']['coordinate']
    now = monotonic()
    if coordinate is not None and not any(
            value is None for value in coordinate):
        state = context.get('ng_relogin') or {}
        if state.get('waiting'):
            resumeAtNearestWaypoint(context)
            logEvent('reloginSuccess', {'attempts': state.get('attempts', 0)})
        context['ng_relogin'] = {}
        return context

    state = context.setdefault('ng_relogin', {})
    if state.get('since') is None:
        state['since'] = now
        return context
    if now - state['since'] < RELOGIN_AFTER_SECONDS:
        return context
    attempts = state.get('attempts', 0)
    if attempts >= RELOGIN_MAX_ATTEMPTS:
        if not state.get('gaveUp'):
            state['gaveUp'] = True
            context['ng_pause'] = True
            logEvent('reloginFailed', {'attempts': attempts})
        return context
    if now < state.get('nextAt', 0):
        return context
    state['waiting'] = True
    state['attempts'] = attempts + 1
    state['nextAt'] = now + RELOGIN_RETRY_SECONDS
    press('enter')
    if state['attempts'] == 1:
        logEvent('reloginAttempt', {})
    return context
