#!/bin/bash
# VOROps host monitoring agent installer.
# Usage: VOROPS_TOKEN=<enrollment_token> bash <(curl -fsSL https://install.vorops.com/install.sh)
#
# Required env:
#   VOROPS_TOKEN          - enrollment token (get from VOROps admin > Clients)
# Optional env:
#   VOROPS_SERVER         - API base URL (default: https://api.vorops.com)
#   VOROPS_DOWNLOAD_URL   - artifact base URL (default: https://download.vorops.com)
#
# JSON extraction via grep -oP uses PCRE (Linux grep). macOS grep lacks -P;
# this script is intended for Linux targets only. A future improvement would be
# to require/install jq and use it for all JSON parsing.
set -euo pipefail

DOWNLOAD_URL="${VOROPS_DOWNLOAD_URL:-https://download.vorops.com}"
SERVER_URL="${VOROPS_SERVER:-https://api.vorops.com}"
TOKEN="${VOROPS_TOKEN:-}"

err() { echo "error: $*" >&2; exit 1; }
log() { echo "[vorops-install] $*"; }

[ -z "$TOKEN" ] && err "VOROPS_TOKEN env var required. Get one from: $SERVER_URL/clients (admin)."

# Re-exec as root, forwarding relevant env vars.
if [ "$(id -u)" -ne 0 ]; then
    log "elevating to root via sudo..."
    exec sudo -E \
        VOROPS_TOKEN="$TOKEN" \
        VOROPS_SERVER="$SERVER_URL" \
        VOROPS_DOWNLOAD_URL="$DOWNLOAD_URL" \
        bash "$0" "$@"
fi

# Detect architecture.
ARCH="$(uname -m)"
case "$ARCH" in
    x86_64|amd64)   GOARCH=amd64 ;;
    aarch64|arm64)  GOARCH=arm64 ;;
    *) err "unsupported arch: $ARCH" ;;
esac

log "detected linux-$GOARCH"

# Working directory for downloaded files; cleaned up on any exit.
WORK_DIR="$(mktemp -d)"
# shellcheck disable=SC2064
trap "rm -rf $WORK_DIR" EXIT

# Download helper: prefer curl, fall back to wget.
download() {
    local url="$1" out="$2"
    if command -v curl >/dev/null 2>&1; then
        curl -fsSL "$url" -o "$out"
    elif command -v wget >/dev/null 2>&1; then
        wget -q "$url" -O "$out"
    else
        err "need curl or wget to download artifacts"
    fi
}

log "downloading binaries from $DOWNLOAD_URL"
download "$DOWNLOAD_URL/vorops-agent-linux-$GOARCH" "$WORK_DIR/vorops-agent"
download "$DOWNLOAD_URL/alloy-linux-$GOARCH"        "$WORK_DIR/alloy"
download "$DOWNLOAD_URL/checksums.txt"              "$WORK_DIR/checksums.txt"

log "verifying checksums"
# checksums.txt format: <sha256>  <filename-as-released>
# We extract the expected hash for each artifact and verify against the local file.
(
    cd "$WORK_DIR"
    grep "vorops-agent-linux-${GOARCH}$" checksums.txt | awk '{print $1 "  vorops-agent"}' | sha256sum -c -
    grep "alloy-linux-${GOARCH}$"        checksums.txt | awk '{print $1 "  alloy"}'        | sha256sum -c -
)

log "installing binaries to /usr/local/bin"
install -m 0755 "$WORK_DIR/vorops-agent" /usr/local/bin/vorops-agent
install -m 0755 "$WORK_DIR/alloy"        /usr/local/bin/alloy

# ---------------------------------------------------------------------------
# Collect system information for enrollment payload.
# ---------------------------------------------------------------------------
log "collecting system info"
HOSTNAME_SHORT="$(hostname -s)"
FQDN="$(hostname -f 2>/dev/null || echo "$HOSTNAME_SHORT")"
OS_NAME="linux"
# /etc/os-release values: strip surrounding quotes if present.
OS_DISTRO="$(grep '^ID=' /etc/os-release 2>/dev/null | cut -d= -f2 | tr -d '"' || echo unknown)"
OS_VERSION="$(grep '^VERSION_ID=' /etc/os-release 2>/dev/null | cut -d= -f2 | tr -d '"' || echo unknown)"
KERNEL="$(uname -r)"
CPU_CORES="$(nproc)"
MEM_KB="$(grep '^MemTotal' /proc/meminfo | awk '{print $2}')"
MEM_BYTES=$(( MEM_KB * 1024 ))
# ip route get gives us the outbound interface IP.
PRIMARY_IP="$(ip -4 -o route get 1.1.1.1 2>/dev/null | awk '{print $7}' || echo "")"

# ---------------------------------------------------------------------------
# Enroll with the VOROps API.
# ---------------------------------------------------------------------------
log "enrolling at $SERVER_URL"
ENROLL_RESP="$(curl -fsSL -X POST "$SERVER_URL/agents/enroll" \
    -H "Content-Type: application/json" \
    -d "$(cat <<ENROLL_JSON
{
  "enrollment_token": "$TOKEN",
  "hostname": "$HOSTNAME_SHORT",
  "fqdn": "$FQDN",
  "system_info": {
    "os": "$OS_NAME",
    "distro": "$OS_DISTRO",
    "version": "$OS_VERSION",
    "kernel": "$KERNEL",
    "arch": "$GOARCH",
    "cpu_cores": $CPU_CORES,
    "memory_bytes": $MEM_BYTES
  },
  "network_info": {
    "primary_ipv4": "$PRIMARY_IP"
  }
}
ENROLL_JSON
)")"

# Extract fields from JSON response via PCRE grep (Linux only; intentional).
AGENT_ID="$(echo "$ENROLL_RESP" | grep -oP '"agent_id":"\K[^"]+'    || true)"
AGENT_TOKEN="$(echo "$ENROLL_RESP" | grep -oP '"agent_token":"\K[^"]+' || true)"
HOST_ID="$(echo "$ENROLL_RESP" | grep -oP '"host_id":"\K[^"]+'     || true)"

[ -z "$AGENT_TOKEN" ] && err "enrollment failed. Server response: $ENROLL_RESP"

# ---------------------------------------------------------------------------
# Write config files.
# ---------------------------------------------------------------------------
log "writing /etc/vorops-agent/"
mkdir -p /etc/vorops-agent /etc/alloy /var/lib/alloy /var/log/vorops-agent

# config.yml — agent runtime configuration (not secret).
cat > /etc/vorops-agent/config.yml <<CONFIG_YML
server_url: $SERVER_URL
poll_interval_seconds: 60
log_level: info
alloy_config_path: /etc/alloy/config.alloy
alloy_reload_command: ["systemctl", "reload", "alloy"]
CONFIG_YML

# state.json — contains agent_token; 0600 so only root can read.
cat > /etc/vorops-agent/state.json <<STATE_JSON
{
  "agent_id": "$AGENT_ID",
  "agent_token": "$AGENT_TOKEN",
  "host_id": "$HOST_ID",
  "last_config_hash": "",
  "enrolled_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
}
STATE_JSON
chmod 0600 /etc/vorops-agent/state.json

# Alloy config placeholder — the agent populates this via polling and then
# triggers an Alloy reload. An empty file lets Alloy start cleanly.
touch /etc/alloy/config.alloy

# ---------------------------------------------------------------------------
# Install systemd units.
# ---------------------------------------------------------------------------
log "installing systemd units"

cat > /etc/systemd/system/vorops-agent.service <<'AGENT_UNIT'
[Unit]
Description=VOROps Host Monitoring Agent
Documentation=https://vorops.com/docs/agent
After=network-online.target alloy.service
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/vorops-agent run
Restart=on-failure
RestartSec=30
User=root
Group=root
NoNewPrivileges=yes
ProtectSystem=full
ProtectHome=yes
ProtectControlGroups=yes
ReadWritePaths=/etc/vorops-agent /etc/alloy /var/log/vorops-agent
PrivateTmp=yes

[Install]
WantedBy=multi-user.target
AGENT_UNIT

cat > /etc/systemd/system/alloy.service <<'ALLOY_UNIT'
[Unit]
Description=Grafana Alloy (managed by vorops-agent)
Documentation=https://grafana.com/docs/alloy/
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/alloy run /etc/alloy/config.alloy --server.http.listen-addr=127.0.0.1:12345 --storage.path=/var/lib/alloy
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=10
User=root
Group=root
NoNewPrivileges=yes
ReadWritePaths=/var/lib/alloy /etc/alloy

[Install]
WantedBy=multi-user.target
ALLOY_UNIT

systemctl daemon-reload
systemctl enable --now alloy.service
systemctl enable --now vorops-agent.service

log "installed successfully"
log "  agent_id:  $AGENT_ID"
log "  host_id:   $HOST_ID"
log "  run: systemctl status vorops-agent"
log "  run: /usr/local/bin/vorops-agent status"
