"""Web-UI-Befehle: Datei-Bridge in den Mainloop.

Die Web-UI (webui/server.py) schreibt Befehle als JSON-Datei, der
Mainloop konsumiert sie hier pro Tick. Kein Socket, kein Threading-
Problem — die Datei ist die einzige Schnittstelle. Fehler beim
Ausfuehren duerfen den Loop nie toeten, darum still (das Event-Log
sagt dem Nutzer, ob es geklappt hat).
"""
import json
from pathlib import Path

from src.gameplay.monitoring import logEvent

COMMAND_FILE = Path('.pilotng-web-command.json')

# Pfade, die die Web-UI per setConfig schreiben darf (Whitelist).
SETTABLE_PREFIXES = (
    'healing.', 'ng_deathConfig.', 'general_hotkeys.', 'auto_hur.',
    'alert.', 'ng_lootRules', 'ng_lootDropUnwanted', 'ng_backpacks.',
    'ng_comboSpells.', 'ui_theme', 'ui_mode', 'ui_glass',
    'allies', 'enemies',
)


def _setPath(target, dottedPath, value):
    """Schreibt value entlang 'a.b.0.c' in ein verschachteltes Dict."""
    keys = dottedPath.split('.')
    node = target
    for key in keys[:-1]:
        if isinstance(node, list):
            node = node[int(key)]
        else:
            node = node.setdefault(key, {})
    last = keys[-1]
    if isinstance(node, list):
        node[int(last)] = value
    else:
        node[last] = value


def _setConfig(uiContext, payload):
    """Generischer Config-Write: Kontext + Profil + Persistenz."""
    path = payload.get('path', '')
    if not any(path.startswith(prefix) for prefix in SETTABLE_PREFIXES):
        return
    value = payload.get('value')
    _setPath(uiContext.context, path, value)
    _setPath(uiContext.enabledProfile['config'], path, value)
    uiContext.db.update(uiContext.enabledProfile)


def _play(uiContext):
    """Wie ui.Context.play(), aber ohne tk-Messagebox (Loop-Thread!)."""
    from src.gameplay.core.middlewares.window import setTibiaWindowMiddleware
    from src.utils.ino import requireArduino
    requireArduino()
    setTibiaWindowMiddleware(uiContext.context)
    if uiContext.context.get('window') is not None:
        uiContext.context['ng_pause'] = False


def consumeWebCommand(uiContext):
    """Wendet einen anstehenden Web-Befehl an (max. einer pro Tick)."""
    if not COMMAND_FILE.exists():
        return uiContext.context
    try:
        command = json.loads(COMMAND_FILE.read_text(encoding='utf-8'))
    except (OSError, ValueError):
        command = None
    try:
        COMMAND_FILE.unlink()
    except OSError:
        pass
    if not isinstance(command, dict):
        return uiContext.context
    action = command.get('action')
    value = bool(command.get('value'))
    try:
        if action == 'play':
            _play(uiContext)
        elif action == 'pause':
            uiContext.pause()
        elif action == 'toggleCavebot':
            uiContext.toggleCavebot(value)
        elif action == 'toggleRunToCreatures':
            uiContext.toggleRunToCreatures(value)
        elif action == 'toggleHealing':
            uiContext.toggleHealingMaster(value)
        elif action == 'toggleCombo':
            uiContext.toggleComboSpells(value)
        elif action == 'toggleRecording':
            uiContext.toggleRecording()
        elif action == 'setConfig':
            _setConfig(uiContext, command)
        else:
            return uiContext.context
        logEvent('webCommand', {'action': action, 'value': value})
    except Exception:  # noqa: BLE001 — der Loop darf nie an der UI haengen
        logEvent('webCommandFailed', {'action': action})
    return uiContext.context
