#!/usr/bin/env bash
# Supervisor del ESCÁNER PIXEL V4 (:8773) — P0 (2026-08-06).
# Reemplaza el nohup suelto de run_pixel.sh, que NO revivía: un SIGSEGV de frida-core dejaba el escáner
# MUERTO hasta reinicio manual (horas de "bloqueo"). Aquí: prep de dispositivos UNA vez + backend con
# RESPAWN (throttle anti-flap) + log con ROTACIÓN (>> en vez de >; no se trunca en cada respawn -> forense).
# NO reinicia el juego si ya está vivo (respeta la sesión). Pensado para lanzarse desde launchd (boot) o a mano.
set -u
HERE="$(cd "$(dirname "$0")" && pwd)"
PY="/Applications/Xcode.app/Contents/Developer/usr/bin/python3"
FS_BIN_NAME="frida-server-17.9.10-android-arm64"
EVONY_ACT="com.topgamesinc.evony/com.topgamesinc.androidplugin.UnityActivity"
PORT=8773
LOG=/tmp/evony_pixel.log
export PATH="/opt/homebrew/bin:/usr/bin:/bin:$PATH"
SCANNER_W="${SCANNER_W:-33201JEHN00951}"; W_WIFI="${W_WIFI:-192.168.0.30:5555}"
SCANNER_E="${SCANNER_E:-32241JEHN24574}"; E_WIFI="${E_WIFI:-192.168.0.31:5555}"
log(){ echo "[supervise $(date '+%F %T')] $*" | tee -a "$LOG"; }

resolve(){   # $1=serial USB preferido  $2=respaldo wifi
  if [ "$(adb -s "$1" get-state 2>/dev/null | tr -d '\r')" = "device" ]; then echo "$1"; return 0; fi
  adb connect "$2" >/dev/null 2>&1; sleep 2
  [ "$(adb -s "$2" get-state 2>/dev/null | tr -d '\r')" = "device" ] && { echo "$2"; return 0; }
  return 1
}

DW="$(resolve "$SCANNER_W" "$W_WIFI")" || { log "ABORT: móvil W no responde (USB ni WiFi)"; exit 1; }
DE="$(resolve "$SCANNER_E" "$E_WIFI")" || { log "ABORT: móvil E no responde (USB ni WiFi)"; exit 1; }
[ -f "$HERE/agent_W.js" ] && [ -f "$HERE/agent_E.js" ] || bash "$HERE/build_agents_v4.sh"

# --- prep de dispositivos (una vez): frida-server + anti-Doze/anti-sleep + wake; Evony SOLO si no corre ---
for serial in "$DW" "$DE"; do
  adb -s "$serial" shell "su -c 'ls /data/local/tmp/frida-server'" >/dev/null 2>&1 || \
    adb -s "$serial" push "$HERE/$FS_BIN_NAME" /data/local/tmp/frida-server >/dev/null 2>&1 || true
  adb -s "$serial" shell "su -c 'chmod 755 /data/local/tmp/frida-server'" >/dev/null 2>&1 || true
  adb -s "$serial" shell "su -c 'netstat -anl 2>/dev/null | grep \":27042 \" | grep LISTEN'" >/dev/null 2>&1 || \
    adb -s "$serial" shell "su -c 'setsid /data/local/tmp/frida-server </dev/null >/dev/null 2>&1 &'" >/dev/null 2>&1 || true
  adb -s "$serial" shell settings put global stay_on_while_plugged_in 3 >/dev/null 2>&1 || true
  adb -s "$serial" shell settings put system screen_off_timeout 1800000 >/dev/null 2>&1 || true
  adb -s "$serial" shell "su -c 'dumpsys deviceidle disable'" >/dev/null 2>&1 || true   # anti-Doze (Android no mata frida/juego en reposo)
  adb -s "$serial" shell "su -c 'settings put global window_animation_scale 0'" >/dev/null 2>&1 || true
  adb -s "$serial" shell input keyevent KEYCODE_WAKEUP >/dev/null 2>&1 || true
  adb -s "$serial" shell pidof com.topgamesinc.evony >/dev/null 2>&1 || \
    adb -s "$serial" shell am start -n "$EVONY_ACT" >/dev/null 2>&1 || true   # lanza SOLO si no está viva
done

BIND="$(tailscale ip -4 2>/dev/null | head -1)"; [ -z "$BIND" ] && BIND=127.0.0.1
log "prep OK (W=$DW E=$DE bind=$BIND:$PORT). Supervisando backend con respawn…"

# --- SUPERVISOR: mantiene el backend vivo; un crash (SIGSEGV frida) -> respawn en 8s (throttle anti-flap) ---
FAILS=0; LAST_START=0
while true; do
  # rotación del log si pasa de 25MB (archiva a .1) -> no crece sin límite, conserva forense
  if [ -f "$LOG" ] && [ "$(stat -f%z "$LOG" 2>/dev/null || echo 0)" -gt 26214400 ]; then mv "$LOG" "$LOG.1" 2>/dev/null || true; fi
  NOW=$(date +%s)
  if [ $((NOW - LAST_START)) -lt 20 ]; then FAILS=$((FAILS+1)); else FAILS=0; fi
  LAST_START=$NOW
  if [ "$FAILS" -ge 5 ]; then log "5 crashes rápidos seguidos -> pausa 120s (anti-flap)"; sleep 120; FAILS=0; fi
  log "(re)lanzando backend en :$PORT"
  SCANNER_W="$DW" SCANNER_E="$DE" ISCOUT_BIND="$BIND" "$PY" "$HERE/iscout_web.py" >> "$LOG" 2>&1
  CODE=$?
  log "backend salió (code=$CODE) -> respawn en 8s"
  lsof -ti :$PORT 2>/dev/null | xargs kill -9 2>/dev/null || true   # libera el puerto por si quedó ocupado
  sleep 8
done
