#!/usr/bin/env bash
# ============================================================================
# Evony Mesh — configuración + funciones de gestión (motor de los shortcuts).
# Editar SOLO aquí si cambian puertos / dispositivos / cuentas.
# ============================================================================
# IMPRESCINDIBLE: al hacer DOBLE-CLIC, el .command corre con un PATH mínimo
# (/usr/bin:/bin:...) que NO incluye adb (/opt/homebrew/bin) ni lsof (/usr/sbin)
# -> los comandos "no hacían nada". Fijamos aquí el PATH completo; lo heredan
# meshctl Y los bot_web.py que lanza (que necesitan adb para hablar con los devices).
export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/sbin:/sbin:/usr/bin:/bin:$PATH"
APP="$HOME/Desktop/Evony/Evony-Mesh"
PY="/usr/bin/python3"
HUB_PORT=8799
HUB_BIND=0.0.0.0
HUB_URL="http://127.0.0.1:$HUB_PORT"
LOGDIR="$APP/logs"
mkdir -p "$LOGDIR" 2>/dev/null
# Credenciales del dashboard/UIs desde un archivo LOCAL no-trackeado. Sin él, sin login.
_HUB_AUTH="$HOME/Desktop/Shortcuts/Mesh/.hub_auth"
[ -f "$_HUB_AUTH" ] && source "$_HUB_AUTH"
# Nodos PUBLICADOS al exterior (Plesk) -> su UI arranca CON login (BOT_USER/BOT_PASS del .hub_auth).
# Los demás siguen sin login (abiertos en el tailnet). space-separated por id.
PUBLISHED_NODES="dasea niteman 2xs"

# nodos:  id | puerto | device(adb) | avd(vacío = dispositivo FÍSICO) | nombre
MESH_NODES=(
  "lume|8792|emulator-6008|evony_hibrid|Lume"
  "dasea|8794|emulator-6004|evony_bot_1|DaSeaDoe"
  "niteman|8793|emulator-6006|evony_bot_2|NiteMan"
  "2xs|8795|100.99.178.20:5555||2XS"
  "rex|8796|192.168.0.30:5555||RexValerius"
  "valk|8797|192.168.0.31:5555||ValkyriaSwift"
)

port_pid(){ lsof -ti tcp:"$1" -sTCP:LISTEN 2>/dev/null | head -1; }
all_ids(){ local n; for n in "${MESH_NODES[@]}"; do echo "${n%%|*}"; done; }

node_field(){ # <id> <1=id|2=port|3=dev|4=avd|5=name>
  local n id port dev avd name
  for n in "${MESH_NODES[@]}"; do IFS='|' read -r id port dev avd name <<<"$n"
    if [ "$id" = "$1" ]; then
      case "$2" in 1) echo "$id";; 2) echo "$port";; 3) echo "$dev";; 4) echo "$avd";; 5) echo "$name";; esac
      return 0
    fi
  done
  return 1
}

start_hub(){
  local pid; pid=$(port_pid "$HUB_PORT")
  if [ -n "$pid" ]; then echo "🟢 hub ya vivo (pid $pid, :$HUB_PORT)"; return 0; fi
  ( cd "$APP" && MESH_HUB_PORT=$HUB_PORT MESH_HUB_BIND=$HUB_BIND \
      MESH_HUB_USER="${MESH_HUB_USER:-}" MESH_HUB_PASS="${MESH_HUB_PASS:-}" \
      BOT_USER="${BOT_USER:-}" BOT_PASS="${BOT_PASS:-}" \
      nohup "$PY" hub.py >"$LOGDIR/hub.log" 2>&1 & )
  sleep 1; echo "▶️  hub arrancado (:$HUB_PORT) — log: $LOGDIR/hub.log"
}
stop_hub(){
  local pid; pid=$(port_pid "$HUB_PORT")
  if [ -n "$pid" ]; then kill "$pid"; echo "⏹  hub parado (pid $pid)"; else echo "⚪ hub ya estaba parado"; fi
}

start_node(){ # <id>   (MESH_FILL=1 en el entorno lo activa; por defecto OFF)
  local id="$1" port dev avd name pid
  port=$(node_field "$id" 2); dev=$(node_field "$id" 3); avd=$(node_field "$id" 4); name=$(node_field "$id" 5)
  [ -z "$port" ] && { echo "❌ nodo desconocido: $id"; return 1; }
  pid=$(port_pid "$port"); [ -n "$pid" ] && { echo "🟢 $name ya vivo (pid $pid, :$port)"; return 0; }
  # Umbral de freeze del watchdog: los Pixels FÍSICOS (avd vacío, más lentos + adb WiFi) tienen
  # stalls transitorios del latido que se auto-recuperan -> 75s evita reinicios en balde. Los
  # emuladores Mac (rápidos) se quedan en 30s (recuperación rápida de freezes reales).
  local wfz; [ -z "$avd" ] && wfz=75 || wfz=30
  # Login del UI: solo para los nodos PUBLICADOS (BOT_USER/BOT_PASS del .hub_auth); el resto sin login.
  local bu="" bp=""
  case " $PUBLISHED_NODES " in *" $id "*) bu="${BOT_USER:-}"; bp="${BOT_PASS:-}";; esac
  # Asignaciones de entorno = prefijos LITERALES (nunca ${x:+VAR=..}, que bash ejecuta como comando).
  # BOT_AVD vacío es inofensivo (solo lo usa full_restart.sh al cold-boot un emulador).
  ( cd "$APP" && BOT_PORT="$port" BOT_BIND=0.0.0.0 BOT_EMULATOR="$dev" BOT_AVD="$avd" \
      BOT_STATE_DIR="$APP/nodes/$id" WATCHDOG_FREEZE_SECS="$wfz" BOT_USER="$bu" BOT_PASS="$bp" \
      MESH_HUB_URL="$HUB_URL" MESH_NODE_ID="$id" MESH_NODE_NAME="$name" MESH_FILL="${MESH_FILL:-0}" \
      nohup "$PY" bot_web.py >"$LOGDIR/$id.log" 2>&1 & )
  case " $PUBLISHED_NODES " in *" $id "*) echo "   (UI con login — nodo publicado)";; esac
  [ -z "$avd" ] && echo "   (watchdog freeze=${wfz}s — Pixel físico)"
  sleep 1; echo "▶️  $name arrancado (:$port, $dev)$( [ "${MESH_FILL:-0}" = 1 ] && echo '  [MESH_FILL=1]') — log: $LOGDIR/$id.log"
}

# Arranque de un nodo EMULADOR asegurando el emulador CON VENTANA visible.
# Si el emulador está caído -> full_restart.sh lo cold-bootea con ventana (+ frida + Evony).
# Si ya está corriendo -> se usa tal cual (no se puede "añadir ventana" a uno headless en marcha;
# para forzar ventana, apágalo antes:  adb -s <dev> emu kill).
start_node_window(){ # <id>
  local id="$1" dev avd name
  dev=$(node_field "$id" 3); avd=$(node_field "$id" 4); name=$(node_field "$id" 5)
  [ -z "$dev" ] && { echo "❌ nodo desconocido: $id"; return 1; }
  if [ -z "$avd" ]; then
    echo "⚠️  $name es un dispositivo FÍSICO (no emulador) — arranque normal."; start_node "$id"; return
  fi
  if adb devices 2>/dev/null | grep -q "^$dev[[:space:]]*device"; then
    echo "ℹ️  emulador $dev ya corriendo (se usa tal cual). Para forzar ventana: adb -s $dev emu kill  y reintenta."
  else
    echo "🖥️  arrancando emulador $dev ($avd) CON VENTANA… (puede tardar ~1-2 min)"
  fi
  ( cd "$APP" && BOT_EMULATOR="$dev" BOT_AVD="$avd" bash full_restart.sh )
  start_node "$id"
}

stop_node(){ # <id>
  local id="$1" port name pid
  port=$(node_field "$id" 2); name=$(node_field "$id" 5)
  [ -z "$port" ] && { echo "❌ nodo desconocido: $id"; return 1; }
  pid=$(port_pid "$port"); if [ -n "$pid" ]; then kill "$pid"; echo "⏹  $name parado (pid $pid)"; else echo "⚪ ${name:-$id} ya estaba parado"; fi
}

wait_node_healthy(){ # <id> [timeout_s]  -> espera a que el nodo enganche y conecte
  local id="$1" to="${2:-150}" port; port=$(node_field "$id" 2)
  local t0=$SECONDS
  # Nodos PUBLICADOS -> /api/status exige login: nos autenticamos una vez y reutilizamos la cookie.
  # Sin esto curl recibía 401 y el chequeo daba SIEMPRE 0 (falso negativo -> "no confirmó en 150s").
  local cj="" auth=()
  case " $PUBLISHED_NODES " in *" $id "*)
    cj="$(mktemp -t meshwait.XXXXXX)"
    curl -s -c "$cj" -o /dev/null --max-time 5 -X POST "http://127.0.0.1:$port/login" \
      --data-urlencode "user=${BOT_USER:-}" --data-urlencode "pass=${BOT_PASS:-}" 2>/dev/null
    auth=(-b "$cj") ;;
  esac
  while [ $((SECONDS - t0)) -lt "$to" ]; do
    local ok
    ok=$(curl -s "${auth[@]}" "http://127.0.0.1:$port/api/status" 2>/dev/null | /usr/bin/python3 -c "import sys,json
try:
  a=(json.load(sys.stdin).get('agent') or {})
  print(1 if a.get('connected')==1 and a.get('ready') else 0)
except Exception: print(0)" 2>/dev/null)
    [ "$ok" = "1" ] && { [ -n "$cj" ] && rm -f "$cj"; return 0; }
    sleep 4
  done
  [ -n "$cj" ] && rm -f "$cj"
  return 1
}

restart_all_staggered(){ # restart de la flota UNO A UNO (evita los kicks del restart simultáneo)
  echo "🔄 Restart ALL (ESCALONADO — uno a uno, esperando cada nodo). Puede tardar varios minutos."
  stop_hub; sleep 2; start_hub; sleep 1
  local id name
  for id in $(all_ids); do
    name=$(node_field "$id" 5)
    echo "── $name ──"
    stop_node "$id"; sleep 2; start_node "$id"
    echo "   esperando a que $name enganche y conecte…"
    if wait_node_healthy "$id" 150; then echo "   ✅ $name operativo"; else echo "   ⚠️ $name no confirmó en 150s (continúo; revísalo)"; fi
  done
  echo; status_all
}

status_all(){
  local pid n id port dev avd name
  echo "── Evony Mesh — estado ──────────────────────────────"
  pid=$(port_pid "$HUB_PORT")
  printf "  %-14s %-7s %s\n" "HUB" ":$HUB_PORT" "$([ -n "$pid" ] && echo "🟢 vivo (pid $pid)  http://100.127.215.100:$HUB_PORT/" || echo "🔴 parado")"
  for n in "${MESH_NODES[@]}"; do IFS='|' read -r id port dev avd name <<<"$n"
    pid=$(port_pid "$port")
    printf "  %-14s %-7s %s\n" "$name" ":$port" "$([ -n "$pid" ] && echo "🟢 vivo (pid $pid)  $dev" || echo "🔴 parado  $dev")"
  done
  echo "─────────────────────────────────────────────────────"
  echo "  URLs: http://100.127.215.100:<puerto>/   (o 192.168.0.18 / 127.0.0.1)"
}
