#!/bin/sh
# streamchecker — instalador de sonda (una línea).
#
#   curl -fsSL https://stream-get.sentrica.cl/install.sh | sudo sh -s -- --enroll <TOKEN> [opciones]
#
# El token lo da el central al "Agregar sonda" (dashboard). La URL del central
# va horneada abajo (CENTRAL) para el SaaS de Sentrica; en on-prem se pasa con
# --central. El script:
#   - detecta arquitectura (amd64/arm64) y baja el binario estático,
#   - crea usuario de sistema + directorios de estado,
#   - instala un unit systemd que reporta al central (dial-home saliente),
#   - opcional --live: instala go2rtc como sidecar para la vista en vivo,
#   - es idempotente: re-correrlo actualiza el binario y conserva el enrolamiento.
#
# Opciones:
#   --enroll TOKEN   token de la sonda (requerido en la primera instalación)
#   --name NAME      nombre en la flota (default: hostname)
#   --central URL    central al que reportar (default: el SaaS de abajo)
#   --live           instala go2rtc + vista en vivo
#   --no-web         sin dashboard local (por defecto sí, en :8080)
#   --web-port N     puerto del dashboard local (default 8080)
#   --streams "..."  streams a monitorear al arranque (URLs separadas por espacio)
#   --version V      versión a instalar (default: latest)
#   --uninstall      quita el servicio y el binario (conserva estado)
set -eu

# ---- valores por defecto (AJUSTAR a tu infra) -------------------------------
CENTRAL="${SC_CENTRAL:-https://stream-hub.sentrica.cl}"      # central SaaS (override: --central o $SC_CENTRAL)
RELEASES="${SC_RELEASES:-https://stream-get.sentrica.cl/bin}" # binarios (override: $SC_RELEASES, ej. staging/on-prem)
CHANNEL="stable"
VERSION="latest"

# ---- rutas -------------------------------------------------------------------
BIN=/usr/local/bin/streamchecker
GO2RTC_BIN=/usr/local/bin/go2rtc
SC_USER=streamchecker
SC_HOME=/var/lib/streamchecker
ETC=/etc/streamchecker
ENVF="$ETC/hub.env"
UNIT=/etc/systemd/system/streamchecker.service
GO2RTC_USER=go2rtc
GO2RTC_HOME=/var/lib/go2rtc
GO2RTC_UNIT=/etc/systemd/system/go2rtc.service

# ---- estado de las opciones --------------------------------------------------
TOKEN=""; NAME=""; STREAMS=""
WEB=1; WEBPORT=8080; LIVE=0; UNINSTALL=0

log()  { printf '\033[1;34m›\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33m!\033[0m %s\n' "$*" >&2; }
die()  { printf '\033[1;31m✗\033[0m %s\n' "$*" >&2; exit 1; }

# ---- parseo de argumentos ----------------------------------------------------
while [ $# -gt 0 ]; do
  case "$1" in
    --enroll)    TOKEN="${2:-}"; shift 2 ;;
    --enroll=*)  TOKEN="${1#*=}"; shift ;;
    --name)      NAME="${2:-}"; shift 2 ;;
    --name=*)    NAME="${1#*=}"; shift ;;
    --central)   CENTRAL="${2:-}"; shift 2 ;;
    --central=*) CENTRAL="${1#*=}"; shift ;;
    --version)   VERSION="${2:-}"; shift 2 ;;
    --version=*) VERSION="${1#*=}"; shift ;;
    --streams)   STREAMS="${2:-}"; shift 2 ;;
    --streams=*) STREAMS="${1#*=}"; shift ;;
    --web-port)  WEBPORT="${2:-}"; shift 2 ;;
    --web-port=*) WEBPORT="${1#*=}"; shift ;;
    --live)      LIVE=1; shift ;;
    --no-web)    WEB=0; shift ;;
    --uninstall) UNINSTALL=1; shift ;;
    -h|--help)   sed -n '2,32p' "$0" 2>/dev/null || true; exit 0 ;;
    *) die "opción desconocida: $1 (usá --help)" ;;
  esac
done

# ---- chequeos base -----------------------------------------------------------
[ "$(id -u)" = 0 ] || die "corré como root: … | sudo sh -s -- --enroll <TOKEN>"
command -v systemctl >/dev/null 2>&1 || die "requiere systemd."
[ "$(uname -s)" = Linux ] || die "solo Linux (esto es una sonda)."
case "$(uname -m)" in
  x86_64|amd64)  ARCH=amd64 ;;
  aarch64|arm64) ARCH=arm64 ;;
  *) die "arquitectura no soportada: $(uname -m) (amd64/arm64)" ;;
esac

# ---- helpers -----------------------------------------------------------------
fetch() { # fetch URL OUT
  if command -v curl >/dev/null 2>&1; then curl -fSL "$1" -o "$2"
  elif command -v wget >/dev/null 2>&1; then wget -qO "$2" "$1"
  else die "necesito curl o wget."; fi
}

verify() { # verify FILE URL — valida checksum si el central publica .sha256
  local sums; sums=$(mktemp)
  if fetch "$2.sha256" "$sums" 2>/dev/null; then
    local want have
    want=$(cut -d' ' -f1 "$sums"); have=$(sha256sum "$1" | cut -d' ' -f1)
    [ "$want" = "$have" ] || { rm -f "$sums"; die "checksum no coincide"; }
    log "checksum OK"
  else
    warn "sin checksum publicado; salteando verificación"
  fi
  rm -f "$sums"
}

ensure_user() { # ensure_user USER HOME
  id "$1" >/dev/null 2>&1 && return 0
  if command -v useradd >/dev/null 2>&1; then
    useradd --system --home-dir "$2" --create-home --shell /usr/sbin/nologin "$1"
  elif command -v adduser >/dev/null 2>&1; then
    adduser -S -H -h "$2" "$1" >/dev/null 2>&1 || adduser --system --no-create-home --home "$2" "$1"
  else
    die "ni useradd ni adduser disponibles."
  fi
}

gen_pass() { head -c 16 /dev/urandom | od -An -tx1 | tr -d ' \n'; }

port_busy() { # port_busy PORT — ¿algo ya escucha en ese puerto (loopback)?
  if command -v ss >/dev/null 2>&1; then ss -ltnH 2>/dev/null | grep -q ":$1 "
  elif command -v netstat >/dev/null 2>&1; then netstat -ltn 2>/dev/null | grep -q ":$1 "
  else return 1; fi
}

# ---- desinstalación ----------------------------------------------------------
if [ "$UNINSTALL" = 1 ]; then
  log "Desinstalando streamchecker…"
  systemctl disable --now streamchecker.service 2>/dev/null || true
  systemctl disable --now go2rtc.service 2>/dev/null || true
  rm -f "$UNIT" "$GO2RTC_UNIT" "$BIN"
  systemctl daemon-reload 2>/dev/null || true
  warn "conservo el estado ($SC_HOME), los secretos ($ETC) y los usuarios; borralos a mano si querés."
  log "Listo."
  exit 0
fi

[ "$LIVE" = 1 ] && [ "$WEB" = 0 ] && die "--live necesita el dashboard local (no combines con --no-web)."

# ---- enrolamiento: token nuevo o reuso del previo (re-run = update) -----------
mkdir -p "$ETC"; chmod 700 "$ETC"
OLD_TOKEN=""; OLD_AUTH=""
[ -f "$ENVF" ] && OLD_TOKEN=$(sed -n 's/^HUB_TOKEN=//p' "$ENVF")
[ -f "$ENVF" ] && OLD_AUTH=$(sed -n 's/^WEB_AUTH=//p' "$ENVF")
[ -z "$TOKEN" ] && TOKEN="$OLD_TOKEN"
[ -n "$TOKEN" ] || die "falta --enroll <TOKEN> (lo da el dashboard al 'Agregar sonda')."
[ -n "$NAME" ] || NAME=$(hostname)

# ---- binario -----------------------------------------------------------------
base="$RELEASES/$CHANNEL"; [ "$VERSION" = latest ] || base="$base/$VERSION"
url="$base/streamchecker-linux-$ARCH"
tmp=$(mktemp)
log "Bajando streamchecker ($ARCH, $CHANNEL/$VERSION)…"
fetch "$url" "$tmp" || die "no pude bajar $url"
verify "$tmp" "$url"
install -m 0755 "$tmp" "$BIN"; rm -f "$tmp"

# ---- usuario + estado --------------------------------------------------------
ensure_user "$SC_USER" "$SC_HOME"
mkdir -p "$SC_HOME"; chown "$SC_USER":"$SC_USER" "$SC_HOME"

# ---- vista en vivo: sticky (un re-run la preserva sin re-pasar --live) --------
# Si ya hay unit de go2rtc o algo escuchando en 1984, mantené la vista en vivo
# aunque no venga --live: así rotar/actualizar la sonda no la desconecta.
if [ "$LIVE" = 0 ] && [ "$WEB" = 1 ] && { [ -f "$GO2RTC_UNIT" ] || port_busy 1984; }; then
  LIVE=1; log "detecté go2rtc existente — mantengo la vista en vivo."
fi

# ---- secretos + flags web ----------------------------------------------------
WEB_AUTH_VALUE=""; WEB_FLAGS=""; STREAM_ARGS=""
if [ "$WEB" = 1 ]; then
  if [ -n "$OLD_AUTH" ]; then WEB_AUTH_VALUE="$OLD_AUTH"; else WEB_AUTH_VALUE="admin:$(gen_pass)"; fi
  WEB_FLAGS=" -web :$WEBPORT -auth \${WEB_AUTH}"
fi
[ -n "$STREAMS" ] && STREAM_ARGS=" $STREAMS"

# ---- go2rtc (sidecar de vista en vivo) ---------------------------------------
# Se resuelve ANTES de escribir el unit para cablear los flags SOLO si go2rtc va
# a estar disponible. Si la descarga falla, la sonda igual queda operativa (sin
# vista en vivo) en vez de abortar toda la instalación.
GO2RTC_SELF_VALUE=""; LIVE_FLAGS=""; GO2RTC_UNIT_WRITTEN=0
if [ "$LIVE" = 1 ]; then
  if port_busy 1984; then
    log "go2rtc ya escucha en 127.0.0.1:1984 — reuso el existente (no lo toco)."
  else
    log "Instalando go2rtc…"
    ensure_user "$GO2RTC_USER" "$GO2RTC_HOME"
    gtmp=$(mktemp)
    if fetch "https://github.com/AlexxIT/go2rtc/releases/latest/download/go2rtc_linux_$ARCH" "$gtmp"; then
      install -m 0755 "$gtmp" "$GO2RTC_BIN"; rm -f "$gtmp"
      mkdir -p "$GO2RTC_HOME"
      printf 'api:\n  listen: "127.0.0.1:1984"\n' > "$GO2RTC_HOME/go2rtc.yaml"
      chown -R "$GO2RTC_USER":"$GO2RTC_USER" "$GO2RTC_HOME"
      cat > "$GO2RTC_UNIT" <<EOF
[Unit]
Description=go2rtc — sidecar de vista en vivo de streamchecker
After=network-online.target
Wants=network-online.target
Before=streamchecker.service

[Service]
Type=simple
User=$GO2RTC_USER
WorkingDirectory=$GO2RTC_HOME
ExecStart=$GO2RTC_BIN -config $GO2RTC_HOME/go2rtc.yaml
Restart=always
RestartSec=3
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=$GO2RTC_HOME
PrivateTmp=true

[Install]
WantedBy=multi-user.target
EOF
      GO2RTC_UNIT_WRITTEN=1
    else
      rm -f "$gtmp"; LIVE=0
      warn "no pude bajar go2rtc (¿sin salida a github.com?) — la sonda queda SIN vista en vivo."
      warn "bajá go2rtc a mano a $GO2RTC_BIN y re-corré con --live para habilitarla."
    fi
  fi
  if [ "$LIVE" = 1 ]; then
    GO2RTC_SELF_VALUE="http://${WEB_AUTH_VALUE}@127.0.0.1:$WEBPORT"
    LIVE_FLAGS=" -go2rtc http://127.0.0.1:1984 -go2rtc-self \${GO2RTC_SELF}"
  fi
fi

# EnvironmentFile: secretos fuera del unit y de `systemctl cat` (0600 root).
umask 077
{
  printf 'HUB_TOKEN=%s\n' "$TOKEN"
  [ -n "$WEB_AUTH_VALUE" ]    && printf 'WEB_AUTH=%s\n' "$WEB_AUTH_VALUE"
  [ -n "$GO2RTC_SELF_VALUE" ] && printf 'GO2RTC_SELF=%s\n' "$GO2RTC_SELF_VALUE"
} > "$ENVF"
chmod 600 "$ENVF"; chown root:root "$ENVF" 2>/dev/null || true

# ---- unit de la sonda --------------------------------------------------------
cat > "$UNIT" <<EOF
[Unit]
Description=streamchecker — sonda ($NAME → $CENTRAL)
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=$SC_USER
EnvironmentFile=$ENVF
ExecStart=$BIN -o none$WEB_FLAGS -state $SC_HOME/streams.json -events $SC_HOME/events.db -metrics 127.0.0.1:9090 -hub $CENTRAL -hub-token \${HUB_TOKEN} -probe-name "$NAME"$LIVE_FLAGS$STREAM_ARGS
Restart=always
RestartSec=3
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=$SC_HOME
PrivateTmp=true

[Install]
WantedBy=multi-user.target
EOF

# ---- arrancar (idempotente: enable para el boot + restart para aplicar) ------
# restart (no `enable --now`) para que un re-run que actualiza el binario
# efectivamente reinicie el servicio con la versión nueva.
systemctl daemon-reload
if [ "$GO2RTC_UNIT_WRITTEN" = 1 ]; then
  systemctl enable go2rtc.service
  systemctl restart go2rtc.service
fi
systemctl enable streamchecker.service
systemctl restart streamchecker.service

# ---- resumen -----------------------------------------------------------------
printf '\n\033[1;32m✓ Sonda instalada.\033[0m\n'
printf '  nombre   : %s\n' "$NAME"
printf '  central  : %s  (aparece en la flota en ~10 s)\n' "$CENTRAL"
[ "$WEB" = 1 ] && printf '  local    : http://<IP-de-este-equipo>:%s  (%s)\n' "$WEBPORT" "$WEB_AUTH_VALUE"
[ "$LIVE" = 1 ] && printf '  vista en vivo: habilitada (go2rtc)\n'
[ "$WEB" = 0 ] && [ -z "$STREAMS" ] && warn "sin --no-web ni --streams: la sonda no monitorea nada hasta cargarle streams."
printf '  logs     : journalctl -u streamchecker -f\n\n'
