#!/usr/bin/env bash
# Instalador del Ejenova MDM Agente para Linux.
#
# Detecta la distro/gestor de paquetes y deja todo listo sin que el usuario
# tenga que instalar ni configurar nada a mano: paquetes de sistema
# (grim/ydotool, solo si la sesión es Wayland), el daemon ydotoold corriendo,
# el binario del Agente descargado, y la primera ejecución (que se registra
# solo y deja su propio arranque automático vía InicioAutomatico.cs).
#
# Uso: ./instalar.sh [URL_BACKEND]
#   URL_BACKEND es opcional — por defecto apunta a producción.
#
# No probado contra una máquina Linux real en esta sesión — mismo criterio
# que el resto del Agente Linux: código completo, pero sin verificación en
# vivo todavía.

set -euo pipefail

# Versión de este SCRIPT (no del binario del Agente, que imprime la suya
# propia por separado) — súbela cada vez que se edite y se vuelva a subir
# a R2, para poder confirmar desde su propia salida si de verdad se
# descargó la versión nueva o quedó una copia vieja en caché/disco.
VERSION_INSTALADOR="1.9"

URL_BACKEND="${1:-https://mdm.api.ejenova.cl}"
# El binario se descarga por una dirección CON la versión en el nombre: una dirección nueva no puede estar guardada en ninguna caché
# (visto en vivo: una caché intermedia entregaba una copia vieja del instalador aunque el servidor ya tenía la nueva).
URL_BINARIO="https://pub-250b4e097aba42e5ac1dad7e6873b3aa.r2.dev/ejenova-mdm-agente-1.0.32"
CARPETA_CONFIG="$HOME/.config/ejenova-mdm"
CARPETA_BIN="$HOME/.local/bin"
RUTA_BINARIO="$CARPETA_BIN/ejenova-mdm-agente"

echo "== Ejenova MDM Agente — instalador Linux v$VERSION_INSTALADOR =="

# --- 1. Detectar tipo de sesión gráfica ---------------------------------
ES_WAYLAND=0
if [ "${XDG_SESSION_TYPE:-}" = "wayland" ] || [ -n "${WAYLAND_DISPLAY:-}" ]; then
  ES_WAYLAND=1
fi

if [ "$ES_WAYLAND" -eq 1 ]; then
  echo "Sesión Wayland detectada."
else
  echo "Sesión X11/Xorg detectada — no hace falta instalar grim/ydotool."
fi

# --- 2. Instalar dependencias de sistema (solo si hace falta Wayland) ---
instalar_paquetes() {
  local paquetes=("$@")
  if command -v apt-get >/dev/null 2>&1; then
    sudo apt-get update -qq
    sudo apt-get install -y "${paquetes[@]}"
  elif command -v dnf >/dev/null 2>&1; then
    sudo dnf install -y "${paquetes[@]}"
  elif command -v yum >/dev/null 2>&1; then
    sudo yum install -y "${paquetes[@]}"
  elif command -v pacman >/dev/null 2>&1; then
    sudo pacman -Sy --noconfirm "${paquetes[@]}"
  elif command -v zypper >/dev/null 2>&1; then
    sudo zypper install -y "${paquetes[@]}"
  else
    echo "ADVERTENCIA: no se reconoció el gestor de paquetes de esta distro."
    echo "Instala manualmente: ${paquetes[*]}"
    return 1
  fi
}

if [ "$ES_WAYLAND" -eq 1 ]; then
  FALTANTES=()
  command -v grim >/dev/null 2>&1 || FALTANTES+=("grim")
  command -v ydotool >/dev/null 2>&1 || FALTANTES+=("ydotool")
  # GStreamer: respaldo para GNOME/KDE (vía xdg-desktop-portal) cuando grim
  # no sirve porque el compositor no implementa wlr-screencopy — no se sabe
  # de antemano cuál de los dos caminos va a hacer falta, así que se
  # asegura igual. Se eligió GStreamer (gst-launch-1.0 + pipewiresrc) en
  # vez de ffmpeg tras verlo fallar en vivo: el ffmpeg de Ubuntu no trae
  # soporte PipeWire compilado — GStreamer con pipewiresrc es justo lo que
  # usa el propio GNOME para compartir pantalla, mucho más confiable acá.
  # No alcanza con chequear que exista gst-launch-1.0 — el plugin
  # pipewiresrc es un paquete aparte que puede faltar igual.
  if ! command -v gst-launch-1.0 >/dev/null 2>&1 || ! gst-inspect-1.0 pipewiresrc >/dev/null 2>&1; then
    FALTANTES+=("gstreamer1.0-tools" "gstreamer1.0-plugins-base" "gstreamer1.0-plugins-good" "gstreamer1.0-pipewire")
  fi

  if [ "${#FALTANTES[@]}" -gt 0 ]; then
    echo "Instalando dependencias faltantes: ${FALTANTES[*]}"
    instalar_paquetes "${FALTANTES[@]}" || echo "No se pudieron instalar solas — el video/control remoto no van a funcionar hasta instalarlas a mano."
  else
    echo "grim, ydotool y GStreamer (gst-launch-1.0) ya estaban instalados."
  fi

  # ydotool necesita su daemon (ydotoold) corriendo para poder inyectar
  # eventos en /dev/uinput — sin él, cada comando "ydotool ..." falla con
  # "Failed to connect socket". El paquete .deb de Ubuntu (a diferencia de
  # lo asumido originalmente acá) YA trae su propia unidad systemd
  # (visto en vivo: "ydotool.service", habilitada automáticamente al
  # instalar el paquete) — crear una unidad propia además de esa duplica
  # el daemon. Se reutiliza la del paquete si existe, y solo se crea una
  # de respaldo si no la trae.
  if command -v ydotoold >/dev/null 2>&1 && command -v systemctl >/dev/null 2>&1; then
    UNIDAD_YDOTOOLD=""
    for candidata in ydotool.service ydotoold.service; do
      if systemctl --user list-unit-files "$candidata" >/dev/null 2>&1 \
        && systemctl --user list-unit-files "$candidata" | grep -q "$candidata"; then
        UNIDAD_YDOTOOLD="$candidata"
        break
      fi
    done

    if [ -z "$UNIDAD_YDOTOOLD" ]; then
      UNIDAD_YDOTOOLD="ydotoold.service"
      mkdir -p "$HOME/.config/systemd/user"
      cat > "$HOME/.config/systemd/user/ydotoold.service" <<'EOF'
[Unit]
Description=ydotoold (daemon de inyeccion de eventos para Ejenova MDM Agente)

[Service]
ExecStart=/usr/bin/ydotoold
Restart=on-failure

[Install]
WantedBy=default.target
EOF
      systemctl --user daemon-reload
    fi

    systemctl --user enable --now "$UNIDAD_YDOTOOLD" || \
      echo "ADVERTENCIA: no se pudo iniciar $UNIDAD_YDOTOOLD como servicio de usuario — el control remoto (mouse/teclado) puede no funcionar."
  elif command -v ydotoold >/dev/null 2>&1; then
    echo "systemd de usuario no disponible — inicia 'ydotoold &' manualmente o agrégalo al arranque de tu sesión."
  fi

  # ydotoold necesita abrir /dev/uinput, que en la mayoría de distros solo
  # permite el grupo "input" — visto en vivo (Ubuntu): el propio paquete
  # avisa esto por consola, pero no lo hace solo. usermod no tiene efecto
  # hasta el próximo inicio de sesión (o reboot): no hay forma de evitar
  # ese paso, es una limitación real del modelo de permisos de Linux, no
  # de este instalador.
  if command -v ydotoold >/dev/null 2>&1 && ! id -nG "$USER" | grep -qw input; then
    echo "Agregando a $USER al grupo 'input' (lo necesita ydotoold para acceder a /dev/uinput)..."
    if sudo usermod -aG input "$USER"; then
      REQUIERE_REINICIO_SESION=1
    else
      echo "ADVERTENCIA: no se pudo agregar al grupo 'input' — el control remoto (mouse/teclado) no va a funcionar hasta hacerlo a mano."
    fi
  fi

  # Visto en vivo (`ydotool mousemove --help`): "You need to disable mouse
  # speed acceleration for correct absolute movement" -- es del propio
  # ydotool, no una suposición. Con aceleración activada (lo normal por
  # defecto), la posición donde termina el cursor puede no coincidir con
  # la que se le pidió a "mousemove -a". Solo aplica a GNOME (el esquema
  # gsettings es específico de GNOME) -- Sway/Hyprland necesitarían el
  # equivalente en su propio archivo de configuración, no cubierto acá.
  if [ "$ES_WAYLAND" -eq 1 ] && command -v gsettings >/dev/null 2>&1 && [[ "${XDG_CURRENT_DESKTOP:-}" == *GNOME* ]]; then
    echo "Desactivando la aceleración del mouse (GNOME) -- ydotool la necesita desactivada para que el mouse remoto apunte al lugar correcto."
    gsettings set org.gnome.desktop.peripherals.mouse accel-profile 'flat' 2>/dev/null \
      || echo "ADVERTENCIA: no se pudo desactivar la aceleración del mouse — la posición del mouse remoto puede seguir desviada."
  fi
fi

# --- 3. Descargar y colocar el binario del Agente -----------------------
# Visto en vivo (Ubuntu): el "curl" del sistema puede ser el paquete Snap,
# cuyo sandbox a veces no puede escribir en la ruta de destino ("client
# returned ERROR on write") — se cae a wget en ese caso en vez de fallar
# directo, y si tampoco hay wget, se explica el paso manual.
#
# Se descarga a un archivo TEMPORAL y se mueve al final con "mv", en vez de
# escribir directo sobre $destino -- visto en vivo: si una corrida anterior
# del Agente sigue corriendo (por el autostart, por ejemplo), el kernel
# bloquea escribir directo sobre ese binario ("El archivo de texto está
# ocupado" / ETXTBSY). "mv" reemplaza el nombre del archivo sin tocar el
# contenido que el proceso viejo todavía tiene abierto, así que funciona
# aunque el Agente anterior siga corriendo -- ese proceso sigue usando su
# copia vieja en memoria hasta que se reinicie solo.
descargar() {
  local url="$1" destino="$2" temporal
  temporal="$(mktemp "${destino}.nuevo.XXXXXX")"

  if command -v curl >/dev/null 2>&1 && curl -fsSL "$url" -o "$temporal"; then
    mv -f "$temporal" "$destino"
    return 0
  fi

  echo "curl falló (en Ubuntu suele ser la versión Snap, con sandbox restringido) — probando con wget..."
  if command -v wget >/dev/null 2>&1 && wget -q "$url" -O "$temporal"; then
    mv -f "$temporal" "$destino"
    return 0
  fi

  rm -f "$temporal"
  echo "ERROR: no se pudo descargar $url con curl ni wget."
  echo "Descárgalo a mano y guárdalo en $destino, luego reintenta este script."
  return 1
}

mkdir -p "$CARPETA_BIN"
echo "Descargando el Agente..."
descargar "$URL_BINARIO" "$RUTA_BINARIO" || exit 1
chmod +x "$RUTA_BINARIO"

# --- 3b. Comando "ejenova-mdm-estado": muestra de un vistazo si el Agente corre ------------------------
# Como el Agente es un servicio en segundo plano, no imprime nada en ninguna terminal: este comando resume su estado.
cat > "$CARPETA_BIN/ejenova-mdm-estado" <<'ESTADO_EOF'
#!/usr/bin/env bash
# Resumen del estado del Ejenova MDM Agente (servicio de usuario).
UNIDAD="ejenova-mdm-agente.service"
LOG="$HOME/.config/ejenova-mdm/agente.log"

echo "== Ejenova MDM Agente =="
if systemctl --user is-active --quiet "$UNIDAD"; then
  echo "Estado:            CORRIENDO"
  echo "Desde:             $(systemctl --user show "$UNIDAD" -p ActiveEnterTimestamp --value)"
else
  echo "Estado:            DETENIDO  (para iniciarlo: systemctl --user start ejenova-mdm-agente)"
fi
echo "Copias corriendo:  $(pgrep -fc 'ejenova-mdm-agente$') (debe ser 1)"
echo "Reinicios por falla: $(systemctl --user show "$UNIDAD" -p NRestarts --value 2>/dev/null)"
if [ -f "$LOG" ]; then
  echo "Versión:           $(grep -o 'Linux v[0-9.]*' "$LOG" | tail -1 | sed 's/^Linux //')"
  echo "Última conexión:   $(grep -E 'Conectado\.|Desconectado|Sin conexión' "$LOG" | tail -1)"
  echo
  echo "--- últimas líneas del registro ---"
  tail -n 8 "$LOG"
  echo
  echo "Para verlo en vivo:  tail -f $LOG"
else
  echo "(todavía no hay registro en $LOG)"
fi
ESTADO_EOF
chmod +x "$CARPETA_BIN/ejenova-mdm-estado"

# --- 4. Configuración -----------------------------------------------------
mkdir -p "$CARPETA_CONFIG"
if [ ! -f "$CARPETA_CONFIG/agente.json" ]; then
  cat > "$CARPETA_CONFIG/agente.json" <<EOF
{"BackendUrl": "$URL_BACKEND"}
EOF
  echo "Configuración creada en $CARPETA_CONFIG/agente.json (BackendUrl=$URL_BACKEND)."
else
  echo "Ya existe una configuración en $CARPETA_CONFIG/agente.json — no se sobrescribe."
fi

# --- 5. Primera ejecución (se registra solo) y arranque permanente -------
# Visto en vivo (LinuxJM, Ubuntu con la terminal como snap): lanzar el Agente con "nohup ... & disown" NO alcanza --
# al cerrar la terminal el sistema cierra todo su grupo de procesos y el Agente se caía con ella, dejando al equipo
# "sin conexión" hasta el próximo inicio de sesión. La solución es que el Agente NO dependa de la terminal: se corre como
# SERVICIO DE USUARIO de systemd, que vive aparte, arranca con la sesión gráfica y se reinicia solo si se cae.
# Si el instalador se corre de nuevo (ej. tras un fix), primero se matan las copias previas (el Agente ya no se duplica
# aunque quedara alguna: tiene un bloqueo de instancia única).
RUTA_LOG="$CARPETA_CONFIG/agente.log"
UNIDAD="ejenova-mdm-agente.service"
CARPETA_UNIDADES="$HOME/.config/systemd/user"
echo "Registrando el equipo (primera ejecución)..."
if [ "$ES_WAYLAND" -eq 1 ]; then
  echo "Si aparece un diálogo del sistema pidiendo compartir pantalla, apruébalo — solo se pide esta vez."
fi

if command -v systemctl >/dev/null 2>&1 && systemctl --user show-environment >/dev/null 2>&1; then
  # Detiene una instalación anterior (servicio o copia suelta) antes de reemplazar el arranque.
  systemctl --user stop "$UNIDAD" 2>/dev/null || true
  pkill -f "$RUTA_BINARIO" 2>/dev/null && sleep 1 || true

  mkdir -p "$CARPETA_UNIDADES"
  cat > "$CARPETA_UNIDADES/$UNIDAD" <<UNIDAD_EOF
[Unit]
Description=Ejenova MDM Agente (soporte remoto)
After=graphical-session.target
PartOf=graphical-session.target
StartLimitIntervalSec=0

[Service]
ExecStart=$RUTA_BINARIO
# Siempre se reinicia si termina por su cuenta (falla o salida inesperada), y nunca se rinde. 75 = "ya hay otra copia corriendo".
Restart=always
RestartSec=5
RestartPreventExitStatus=75
StandardOutput=append:$RUTA_LOG
StandardError=append:$RUTA_LOG

[Install]
WantedBy=graphical-session.target
UNIDAD_EOF
  # El autostart XDG que dejaba el propio Agente sobra con el servicio (se levantaría dos veces).
  rm -f "$HOME/.config/autostart/ejenova-mdm-agente.desktop"
  systemctl --user daemon-reload
  if systemctl --user enable --now "$UNIDAD"; then
    sleep 3
    if systemctl --user is-active --quiet "$UNIDAD"; then
      echo "Agente corriendo como servicio de usuario (independiente de esta terminal). Log en $RUTA_LOG."
      echo "Para ver su estado: systemctl --user status $UNIDAD"
    else
      echo "ADVERTENCIA: el servicio se creó pero no quedó activo. Revisa: systemctl --user status $UNIDAD  y  $RUTA_LOG"
    fi
  else
    echo "ADVERTENCIA: no se pudo habilitar el servicio de usuario ($UNIDAD)."
  fi
else
  # Sin systemd de usuario: respaldo con "setsid" (sesión propia, no atada a la terminal) + autostart XDG del propio Agente.
  echo "systemd de usuario no disponible — se usa un arranque simple (si cierras sesión se detiene hasta el próximo inicio)."
  pkill -f "$RUTA_BINARIO" 2>/dev/null && sleep 1 || true
  setsid nohup "$RUTA_BINARIO" >"$RUTA_LOG" 2>&1 < /dev/null &
  sleep 3
  echo "Agente corriendo en segundo plano. Log en $RUTA_LOG."
fi

echo ""
echo "Listo. El equipo debería aparecer en el listado de Equipos de Ejenova MDM."
if [ "$ES_WAYLAND" -eq 1 ]; then
  echo "En compositores wlroots (Sway, Hyprland, etc.) el video/control remoto funcionan sin avisos."
  echo "En GNOME/KDE, la primera vez que un Técnico se conecte va a aparecer un diálogo del sistema pidiendo compartir pantalla — apruébalo una sola vez, no se vuelve a pedir después."
fi
if [ "${REQUIERE_REINICIO_SESION:-0}" -eq 1 ]; then
  echo ""
  echo "IMPORTANTE: cierra sesión (o reinicia) antes de probar el control remoto — el permiso de grupo 'input' recién agregado no aplica hasta la próxima sesión."
fi
echo "El Agente arrancará solo en cada inicio de sesión gráfica y no se cierra al cerrar la terminal."
echo "Para ver su estado en cualquier momento:  $CARPETA_BIN/ejenova-mdm-estado"
