#!/bin/sh
# Remote Control Support — agent installer for macOS and Linux.
#
# Served from the hub, which substitutes HUB and TOKEN below before sending it,
# so the published one-liner carries the enrolment token in its URL:
#
#   curl -fsSL https://support.freakma.com/install.sh?token=TOKEN | sh
#
# Fetched without a token it still works, taking one as an argument instead:
#
#   curl -fsSL https://support.freakma.com/install.sh | sh -s -- TOKEN
#
# Everything lands under ~/.rcs-agent. Nothing here needs root.

set -eu

HUB="https://support.freakma.com"
TOKEN=""

# Written long-hand rather than `[ $# -gt 0 ] && TOKEN="$1"`: under `set -e` the
# short-circuit form leaves the script's exit status at 1 when no argument was
# given, which is the normal case for the piped one-liner.
if [ $# -gt 0 ]; then TOKEN="$1"; fi

INSTALL_DIR="$HOME/.rcs-agent"
AGENT="$INSTALL_DIR/agent.js"
CONFIG="$INSTALL_DIR/config.json"
SERVICE_NAME="rcs-agent"

say()  { printf '%s\n' "$*"; }
warn() { printf '\033[33m!\033[0m %s\n' "$*" >&2; }
die()  { printf '\033[31mx\033[0m %s\n' "$*" >&2; exit 1; }
step() { printf '\033[36m>\033[0m %s\n' "$*"; }

[ -n "$TOKEN" ] || die "no enrolment token. Open the invite link on this machine, or pass one:
  curl -fsSL $HUB/install.sh | sh -s -- YOUR_TOKEN"

case "$(uname -s)" in
  Darwin) PLATFORM=macos ;;
  Linux)  PLATFORM=linux ;;
  *)      die "$(uname -s) is not supported by this script — see $HUB/docs" ;;
esac

# ------------------------------------------------------------------ node

# The agent uses the global WebSocket, which is only on by default from Node 22.
command -v node >/dev/null 2>&1 || die "Node.js 22 or newer is required and was not found.
  macOS:  brew install node        (or https://nodejs.org)
  Debian: curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - && sudo apt install -y nodejs
  Fedora: sudo dnf install nodejs"

NODE_MAJOR=$(node -p 'process.versions.node.split(".")[0]' 2>/dev/null || echo 0)
[ "$NODE_MAJOR" -ge 22 ] 2>/dev/null || die "Node.js 22 or newer is required — this machine has $(node -v).
  Upgrade it, or run the agent on another machine on this LAN and point it here:
  node agent.js enroll <link> --vnc-host $(hostname)"

# ------------------------------------------------------------------- vnc

# Advisory only: the VNC server can be started after enrolment, and on a fresh
# macOS the Screen Sharing toggle is usually the last thing someone does.
vnc_listening() {
  if command -v nc >/dev/null 2>&1; then nc -z -w 2 127.0.0.1 5900 >/dev/null 2>&1; return $?; fi
  return 1
}

if ! vnc_listening; then
  case "$PLATFORM" in
    macos) warn "nothing is listening on 127.0.0.1:5900 — turn on System Settings > General > Sharing > Screen Sharing" ;;
    linux) warn "nothing is listening on 127.0.0.1:5900 — start one, e.g. x11vnc -localhost -rfbport 5900" ;;
  esac
fi

# --------------------------------------------------------------- install

step "installing to $INSTALL_DIR"
mkdir -p "$INSTALL_DIR"
curl -fsSL "$HUB/download/agent.js" -o "$AGENT" || die "could not download the agent from $HUB"

step "enrolling with $HUB"
node "$AGENT" enroll "$HUB/enroll/$TOKEN" --config "$CONFIG"

# --------------------------------------------------------------- service

NODE_BIN=$(command -v node)

install_launchd() {
  PLIST="$HOME/Library/LaunchAgents/com.freakma.rcs-agent.plist"
  mkdir -p "$HOME/Library/LaunchAgents"
  cat > "$PLIST" <<PLIST_EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key><string>com.freakma.rcs-agent</string>
  <key>ProgramArguments</key>
  <array>
    <string>$NODE_BIN</string>
    <string>$AGENT</string>
    <string>run</string>
    <string>--config</string>
    <string>$CONFIG</string>
  </array>
  <key>RunAtLoad</key><true/>
  <key>KeepAlive</key><true/>
  <key>StandardOutPath</key><string>$INSTALL_DIR/agent.log</string>
  <key>StandardErrorPath</key><string>$INSTALL_DIR/agent.log</string>
</dict>
</plist>
PLIST_EOF
  launchctl unload "$PLIST" >/dev/null 2>&1 || true
  launchctl load "$PLIST"
  say ""
  say "Running as a launchd agent. Useful commands:"
  say "  launchctl unload $PLIST     # stop"
  say "  launchctl load   $PLIST     # start"
  say "  tail -f $INSTALL_DIR/agent.log"
}

install_systemd_user() {
  UNIT_DIR="$HOME/.config/systemd/user"
  mkdir -p "$UNIT_DIR"
  cat > "$UNIT_DIR/$SERVICE_NAME.service" <<UNIT_EOF
[Unit]
Description=Remote Control Support agent
After=network-online.target

[Service]
ExecStart=$NODE_BIN $AGENT run --config $CONFIG
Restart=always
RestartSec=5

[Install]
WantedBy=default.target
UNIT_EOF
  systemctl --user daemon-reload
  systemctl --user enable --now "$SERVICE_NAME"
  say ""
  say "Running as a systemd user service. Useful commands:"
  say "  systemctl --user status $SERVICE_NAME"
  say "  journalctl --user -u $SERVICE_NAME -f"
  # Without lingering the service dies at logout, which is exactly when remote
  # support is most likely to be needed.
  loginctl enable-linger "$(id -un)" >/dev/null 2>&1 \
    || warn "run 'sudo loginctl enable-linger $(id -un)' so the agent survives logout"
}

install_manual() {
  say ""
  say "No supported service manager found. Start the agent by hand:"
  say "  node $AGENT run --config $CONFIG"
}

step "setting it to start automatically"
case "$PLATFORM" in
  macos) install_launchd ;;
  linux)
    if command -v systemctl >/dev/null 2>&1 && systemctl --user show-environment >/dev/null 2>&1; then
      install_systemd_user
    else
      install_manual
    fi
    ;;
esac

say ""
say "Done. This machine is registered and should now appear in the console."
say "Config: $CONFIG"
