#!/usr/bin/env bash
set -euo pipefail

# Appmint hub agent installer (Linux).
#
# Bootstraps any Debian / Ubuntu / Armbian box into a working hub.
# Mini PC, old desktop, Pi, Orange Pi — anything that runs Node 20.
#
#   - installs Node 20 if missing
#   - drops the agent under /opt/appmint-hub
#   - drops the systemd unit
#   - runs the setup wizard so the operator pastes the hub API key
#   - starts + enables the service
#
# Usage:
#   curl -sSL https://appmint.io/hub | sudo bash
# or for a local clone:
#   sudo ./scripts/install.sh
#
# Re-running upgrades the binary in place; config is preserved.

INSTALL_DIR="/opt/appmint-hub"
CONFIG_DIR="/etc/appmint-hub"
SERVICE_FILE="/etc/systemd/system/appmint-hub.service"
NODE_MAJOR="20"

# Pinned at publish time by deploy.js. An installer fetched from the CDN only
# ever installs the build it shipped with, so running the same curl command
# twice cannot quietly produce two different agents. Override to install a
# specific release:  HUB_VERSION=0.1.0 sudo ./install.sh
HUB_VERSION="${HUB_VERSION:-dev}"
RELEASE_BASE_URL="${RELEASE_BASE_URL:-__RELEASE_BASE_URL__}"

require_root() {
  if [ "${EUID}" -ne 0 ]; then
    echo "install: must run as root (use sudo)" >&2
    exit 1
  fi
}

install_node() {
  if command -v node >/dev/null 2>&1; then
    local current
    current="$(node -v | sed 's/^v//' | cut -d. -f1)"
    if [ "${current}" -ge "${NODE_MAJOR}" ]; then
      return
    fi
  fi
  echo "install: installing Node ${NODE_MAJOR}…"
  curl -fsSL "https://deb.nodesource.com/setup_${NODE_MAJOR}.x" | bash -
  apt-get install -y nodejs
}

install_agent() {
  echo "install: copying agent to ${INSTALL_DIR}…"
  mkdir -p "${INSTALL_DIR}"
  # If running from a local clone, copy from the script's parent dir.
  local src
  src="$(cd "$(dirname "$0")/.." && pwd)"
  if [ -f "${src}/package.json" ] && grep -q '"name": "hub-agent"' "${src}/package.json"; then
    rsync -a --delete \
      --exclude=node_modules --exclude=dist \
      "${src}/" "${INSTALL_DIR}/"
    cd "${INSTALL_DIR}"
    # Install full deps (TS + @types live in devDependencies and are needed
    # to compile), build, then prune dev deps so production runtime is lean.
    npm ci
    npm run build
    npm prune --omit=dev
  else
    install_agent_from_release
  fi
}

# Download the published tarball. It already contains a compiled dist/, so the
# client machine never needs TypeScript — only the two runtime dependencies.
install_agent_from_release() {
  if [ "${RELEASE_BASE_URL}" = "__RELEASE_BASE_URL__" ]; then
    echo "install: this installer was not published (no release URL baked in)." >&2
    echo "         Run it from a local clone, or download it from the CDN." >&2
    exit 1
  fi

  local tarball="hub-agent-${HUB_VERSION}.tar.gz"
  local tmp
  tmp="$(mktemp -d)"
  trap 'rm -rf "${tmp}"' RETURN

  echo "install: downloading hub-agent ${HUB_VERSION}…"
  curl -fsSL "${RELEASE_BASE_URL}/${tarball}" -o "${tmp}/${tarball}"

  # Verify against the checksum published alongside it. This script is run as
  # root straight off a URL, so a corrupted or swapped tarball is worth more
  # than a shrug — a mismatch stops the install rather than executing it.
  if curl -fsSL "${RELEASE_BASE_URL}/release.json" -o "${tmp}/release.json" 2>/dev/null; then
    local want have
    want="$(sed -n 's/.*"sha256"[[:space:]]*:[[:space:]]*"\([a-f0-9]*\)".*/\1/p' "${tmp}/release.json")"
    have="$(sha256sum "${tmp}/${tarball}" | cut -d' ' -f1)"
    if [ -n "${want}" ] && [ "${want}" != "${have}" ]; then
      echo "install: checksum mismatch for ${tarball} — refusing to install." >&2
      echo "         expected ${want}" >&2
      echo "         got      ${have}" >&2
      exit 1
    fi
  fi

  tar -xzf "${tmp}/${tarball}" -C "${tmp}"
  rsync -a --delete --exclude=node_modules "${tmp}/hub-agent/" "${INSTALL_DIR}/"
  cd "${INSTALL_DIR}"
  # dist/ is prebuilt, so this pulls runtime deps only — no toolchain needed.
  npm install --omit=dev --no-audit --no-fund
}

install_service() {
  echo "install: dropping systemd unit…"
  mkdir -p "${CONFIG_DIR}"
  cp "${INSTALL_DIR}/systemd/appmint-hub.service" "${SERVICE_FILE}"
  systemctl daemon-reload
}

run_wizard_if_needed() {
  # No existing config = first install, run wizard.
  if [ ! -f "${CONFIG_DIR}/config.json" ]; then
    echo "install: no existing config — running setup wizard"
    node "${INSTALL_DIR}/dist/setup.js" --out="${CONFIG_DIR}/config.json"
    return
  fi

  # Show the operator what's there and ask one question. Default = keep.
  echo ""
  echo "Existing config found at ${CONFIG_DIR}/config.json:"
  node -e "const c=require('${CONFIG_DIR}/config.json'); console.log('  hub:    '+c.hubName); console.log('  org:    '+c.orgId); console.log('  server: '+c.serverUrl);" 2>/dev/null || true
  echo ""
  echo "  1) Keep existing config — just update the software  [default]"
  echo "  2) Reconfigure — change credentials / server URL"
  echo ""
  printf "Choose 1 or 2 [1]: "
  read choice
  choice="${choice:-1}"
  if [ "$choice" = "2" ]; then
    node "${INSTALL_DIR}/dist/setup.js" --out="${CONFIG_DIR}/config.json"
  else
    echo "install: keeping existing config — software-only update"
  fi
}

install_cli_wrapper() {
  # Drop a tiny wrapper at /usr/local/bin/hub-agent so the operator can
  # type `sudo hub-agent status` instead of `sudo node /opt/.../cli.js status`.
  local wrapper="/usr/local/bin/hub-agent"
  echo "install: dropping CLI wrapper at ${wrapper}"
  mkdir -p /usr/local/bin
  cat > "${wrapper}" <<EOF
#!/usr/bin/env bash
exec node "${INSTALL_DIR}/dist/cli.js" "\$@"
EOF
  chmod +x "${wrapper}"
}

start_service() {
  echo "install: enabling + starting appmint-hub…"
  systemctl enable --now appmint-hub
  sleep 1
}

print_summary() {
  echo ""
  echo "=========================================================="
  echo "  appmint-hub installed and RUNNING"
  echo "=========================================================="
  echo ""
  echo "Service:    appmint-hub  (systemd)"
  echo "Status:     systemctl status appmint-hub"
  echo "Auto-start: yes — will start automatically on every boot."
  echo ""
  echo "Files:"
  echo "  install:  ${INSTALL_DIR}"
  echo "  config:   ${CONFIG_DIR}/config.json"
  echo "  logs:     journalctl -u appmint-hub  (or -f to follow)"
  echo ""
  echo "Commands (run from anywhere):"
  echo "  sudo hub-agent status        Connection state + config + recent log"
  echo "  sudo hub-agent logs -f       Follow the log live"
  echo "  sudo hub-agent devices       List configured + USB-detected devices"
  echo "  sudo hub-agent setup         Reconfigure credentials / server URL"
  echo "  sudo hub-agent update        Update software (preserves config)"
  echo "  sudo hub-agent restart       Bounce the service"
  echo "  sudo hub-agent help          Full command list"
  echo ""
  echo "Verify it's connected:  sudo hub-agent status"
  echo "Or check the admin UI:  Operations → Devices → Hubs"
  echo ""
}

main() {
  require_root
  install_node
  install_agent
  install_service
  install_cli_wrapper
  run_wizard_if_needed
  start_service
  print_summary
}

main "$@"
