"""Session-Rhythmus: menschliche Spiel-/Pausenzeiten.

Ablauf pro Zyklus: hunten → in die Safe-Zone laufen (Depot/Temple-Label)
→ ausloggen → offline warten → wieder einloggen → von vorn. Jede
Phasenlaenge bekommt pro Zyklus einen Zufalls-Jitter (Hunt ±30 Min,
Offline ±10 Min), damit kein metronomer 24/7-Rhythmus entsteht.

Sicherheitsregeln:
- Logout nur in der Safe-Zone (Label depot/dp/depositer/temple/safe/pz),
  nie mitten im Feld. Safe-Zone nicht erreichbar → pausieren + Event.
- Offline/ReLogin laeuft im pausierten Loop-Zweig; Keep-Alive wird in
  diesen Phasen unterbunden (Pfeiltasten im Char-Select waeren fatal).
- Re-Login per Enter bis die Koordinate wieder da ist; danach geht es
  zum Start-Label weiter.
"""
import random
from time import monotonic

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

SAFE_LABELS = ('depot', 'dp', 'depositer', 'temple', 'safe', 'pz')
SAFE_TIMEOUT_SECONDS = 600
LOGOUT_TIMEOUT_SECONDS = 90
LOGOUT_MAX_ATTEMPTS = 5
RELOGIN_RETRY_SECONDS = 60
RELOGIN_MAX_ATTEMPTS = 6


def _cycleDurations(session):
    hunt = max(5, session.get('huntMinutes', 240) + random.randint(-30, 30)) * 60
    offline = max(
        5, session.get('offlineMinutes', 30) + random.randint(-10, 10)) * 60
    return hunt, offline


def _labelIndex(items, labels):
    return next(
        (index for index, waypoint in enumerate(items)
         if (waypoint.get('label') or '').lower() in labels),
        None,
    )


def sessionRhythm(context):
    """Loop-Hook: steuert Hunt/Safe/Logout/Offline/ReLogin-Phasen."""
    session = context.get('ng_session')
    if not session or not session.get('enabled'):
        return context
    state = session.setdefault('state', 'hunting')
    if state == 'paused':
        return context
    now = monotonic()
    coordinate = context['ng_radar']['coordinate']
    waypoints = context['ng_cave']['waypoints']
    items = waypoints['items']

    if state == 'hunting':
        session.setdefault('phaseStartedAt', now)
        session.setdefault('cycle', _cycleDurations(session))
        if now - session['phaseStartedAt'] < session['cycle'][0]:
            return context
        safeIndex = _labelIndex(items, SAFE_LABELS)
        if safeIndex is None:
            session['state'] = 'paused'
            context['ng_pause'] = True
            logEvent('sessionNoSafeLabel', {})
            return context
        waypoints['currentIndex'] = safeIndex
        waypoints['state'] = None
        session['state'] = 'goSafe'
        session['safeIndex'] = safeIndex
        session['safeDeadline'] = now + SAFE_TIMEOUT_SECONDS
        logEvent('sessionGoSafe', {
            'label': items[safeIndex].get('label')})
        return context

    if state == 'goSafe':
        target = items[session['safeIndex']].get('coordinate')
        arrived = (
            coordinate is not None and target is not None
            and not any(value is None for value in coordinate)
            and not any(value is None for value in target)
            and abs(coordinate[0] - target[0]) <= 2
            and abs(coordinate[1] - target[1]) <= 2
            and coordinate[2] == target[2]
        )
        if arrived:
            press('esc')
            hotkey('ctrl', 'q')
            session['state'] = 'logout'
            session['logoutDeadline'] = now + LOGOUT_TIMEOUT_SECONDS
            session['logoutAttempts'] = 1
            logEvent('sessionLogout', {})
            return context
        if now > session['safeDeadline']:
            session['state'] = 'paused'
            context['ng_pause'] = True
            logEvent('sessionSafeTimeout', {})
        return context

    if state == 'logout':
        if coordinate is None:
            session['state'] = 'offline'
            session['offlineUntil'] = now + session['cycle'][1]
            context['ng_pause'] = True
            logEvent('sessionOffline', {
                'minutes': round(session['cycle'][1] / 60)})
            return context
        if now > session['logoutDeadline']:
            if session['logoutAttempts'] >= LOGOUT_MAX_ATTEMPTS:
                session['state'] = 'paused'
                context['ng_pause'] = True
                logEvent('sessionLogoutFailed', {})
                return context
            hotkey('ctrl', 'q')
            session['logoutAttempts'] += 1
            session['logoutDeadline'] = now + LOGOUT_TIMEOUT_SECONDS
        return context

    if state == 'offline':
        if now < session['offlineUntil']:
            return context
        press('enter')
        session['state'] = 'relogin'
        session['reloginAttempts'] = 1
        session['reloginDeadline'] = now + RELOGIN_RETRY_SECONDS
        return context

    if state == 'relogin':
        if coordinate is not None and not any(
                value is None for value in coordinate):
            session['state'] = 'hunting'
            session['phaseStartedAt'] = now
            session['cycle'] = _cycleDurations(session)
            waypoints['currentIndex'] = _labelIndex(items, ('start',)) or 0
            waypoints['state'] = None
            context['ng_pause'] = False
            logEvent('sessionResume', {})
            return context
        if now > session['reloginDeadline']:
            if session['reloginAttempts'] >= RELOGIN_MAX_ATTEMPTS:
                session['state'] = 'paused'
                logEvent('sessionReloginFailed', {})
                return context
            press('enter')
            session['reloginAttempts'] += 1
            session['reloginDeadline'] = now + RELOGIN_RETRY_SECONDS
        return context

    return context
