#!/bin/sh
# dbagent installer — DBMonitor local collector
#
#   curl -fsSL https://agent.meandyoutechsolutions.com.br/download/install.sh | sh
#
# Installs the dbagent static binary, a skeleton /etc/dbagent/agent.toml, and a systemd
# service. The agent reads ONLY from your SQL Server and pushes diagnostics to DBMonitor;
# your database credentials never leave your environment.
#
# Tunables (environment variables):
#   DBAGENT_API_KEY     pre-seed the per-tenant API key (skips the prompt)
#   DBAGENT_SIGNUP_CODE on-site self-registration: with this partner code (and no API key)
#                       the installer registers a fresh tenant and receives its ingest key.
#                       Optional companions: DBAGENT_COMPANY, DBAGENT_EMAIL, DBAGENT_REGISTER_URL
#   DBAGENT_VERSION     version to install (default: latest)
#   DBAGENT_BASE_URL    download host (default: the DBMonitor download dir)
#   DBAGENT_INGEST_URL  override the ingest endpoint baked into agent.toml
#   DBAGENT_BIN_DIR     install dir for the binary (default: /usr/local/bin)
#   DBAGENT_CONF_DIR    config dir (default: /etc/dbagent)
#   DBAGENT_LOCAL_DIST  install from this local dist/ dir instead of downloading
#   DBAGENT_NO_SERVICE  set to 1 to skip systemd service install/enable
#
# Subcommands:  install.sh --uninstall   remove binary, service (keeps config+data)
set -eu

# ---- defaults ---------------------------------------------------------------
BASE_URL="${DBAGENT_BASE_URL:-https://agent.meandyoutechsolutions.com.br/download}"
VERSION="${DBAGENT_VERSION:-latest}"
BIN_DIR="${DBAGENT_BIN_DIR:-/usr/local/bin}"
CONF_DIR="${DBAGENT_CONF_DIR:-/etc/dbagent}"
INGEST_URL="${DBAGENT_INGEST_URL:-https://agent.meandyoutechsolutions.com.br/api/v1/ingest}"
SERVICE_NAME="dbagent"
UNIT_PATH="/etc/systemd/system/${SERVICE_NAME}.service"

# ---- pretty output ----------------------------------------------------------
if [ -t 1 ]; then B="$(printf '\033[1m')"; G="$(printf '\033[32m')"; Y="$(printf '\033[33m')"; R="$(printf '\033[31m')"; N="$(printf '\033[0m')"; else B=; G=; Y=; R=; N=; fi
info() { printf '%s==>%s %s\n' "$G" "$N" "$*"; }
warn() { printf '%s warning:%s %s\n' "$Y" "$N" "$*" >&2; }
die()  { printf '%serror:%s %s\n' "$R" "$N" "$*" >&2; exit 1; }

# ---- privilege escalation ---------------------------------------------------
# Escalate only when a target dir actually needs root. Rootless / custom-prefix
# installs (writable DBAGENT_BIN_DIR + DBAGENT_CONF_DIR) run without sudo.
writable_dir() { d="$1"; while [ ! -e "$d" ]; do d="$(dirname "$d")"; done; [ -w "$d" ]; }
SUDO=
if [ "$(id -u)" -ne 0 ]; then
  need_root=0
  writable_dir "$BIN_DIR"  || need_root=1
  writable_dir "$CONF_DIR" || need_root=1
  [ "${DBAGENT_NO_SERVICE:-0}" = "1" ] || writable_dir "/etc/systemd/system" || need_root=1
  if [ "$need_root" -eq 1 ]; then
    command -v sudo >/dev/null 2>&1 || die "this installer needs root; re-run as root or install sudo"
    SUDO="sudo"
  fi
fi
run() { if [ -n "$SUDO" ]; then $SUDO "$@"; else "$@"; fi; }

# ---- detect arch ------------------------------------------------------------
detect_arch() {
  m="$(uname -m)"
  case "$m" in
    x86_64|amd64)        echo amd64 ;;
    aarch64|arm64)       echo arm64 ;;
    *) die "unsupported architecture: $m (dbagent ships linux amd64/arm64 only)" ;;
  esac
}

# ---- fetch helper (curl or wget) -------------------------------------------
fetch() { # fetch <url> <dest>
  if command -v curl >/dev/null 2>&1; then
    curl -fsSL "$1" -o "$2"
  elif command -v wget >/dev/null 2>&1; then
    wget -qO "$2" "$1"
  else
    die "need curl or wget to download"
  fi
}

# ---- checksum verify --------------------------------------------------------
sha256_of() { # sha256_of <file> -> hex
  if command -v sha256sum >/dev/null 2>&1; then sha256sum "$1" | awk '{print $1}'
  elif command -v shasum   >/dev/null 2>&1; then shasum -a 256 "$1" | awk '{print $1}'
  else die "need sha256sum or shasum to verify the download"; fi
}

verify() { # verify <file> <sums_file> <name_in_sums>
  want="$(awk -v f="$3" '$2 == f || $2 == "*"f {print $1}' "$2" | head -n1)"
  [ -n "$want" ] || die "no checksum for $3 in SHA256SUMS"
  got="$(sha256_of "$1")"
  [ "$want" = "$got" ] || die "checksum mismatch for $3 (want $want, got $got)"
  info "checksum OK ($3)"
}

# ---- uninstall --------------------------------------------------------------
uninstall() {
  info "stopping and removing the dbagent service"
  if command -v systemctl >/dev/null 2>&1; then
    run systemctl disable --now "${SERVICE_NAME}.service" 2>/dev/null || true
    run rm -f "$UNIT_PATH"
    run systemctl daemon-reload || true
  fi
  run rm -f "${BIN_DIR}/dbagent"
  info "removed binary and service. Config kept at ${CONF_DIR} — delete manually if desired."
  exit 0
}

[ "${1:-}" = "--uninstall" ] && uninstall
[ "${1:-}" = "--help" ] && { sed -n '2,30p' "$0" | sed 's/^# \{0,1\}//'; exit 0; }

# ---- read a value interactively (works under `curl | sh`) -------------------
ask() { # ask <prompt> ; echoes answer (empty if non-interactive)
  if [ -r /dev/tty ]; then
    printf '%s' "$1" >/dev/tty
    IFS= read -r _ans </dev/tty || _ans=
    echo "$_ans"
  else
    echo ""
  fi
}

# ============================================================================
ARCH="$(detect_arch)"
ASSET="dbagent-linux-${ARCH}"
info "installing dbagent (${VERSION}, linux/${ARCH})"

TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT

# --- obtain binary + checksums (download, or copy from local dist) ----------
if [ -n "${DBAGENT_LOCAL_DIST:-}" ]; then
  [ -f "${DBAGENT_LOCAL_DIST}/${ASSET}" ] || die "no ${ASSET} in ${DBAGENT_LOCAL_DIST}"
  cp "${DBAGENT_LOCAL_DIST}/${ASSET}" "$TMP/$ASSET"
  if [ -f "${DBAGENT_LOCAL_DIST}/SHA256SUMS" ]; then
    cp "${DBAGENT_LOCAL_DIST}/SHA256SUMS" "$TMP/SHA256SUMS"
    verify "$TMP/$ASSET" "$TMP/SHA256SUMS" "$ASSET"
  else
    warn "no SHA256SUMS in local dist — skipping checksum verification"
  fi
else
  if [ "$VERSION" = latest ]; then urlbase="$BASE_URL"; else urlbase="$BASE_URL/$VERSION"; fi
  info "downloading ${urlbase}/${ASSET}"
  fetch "${urlbase}/${ASSET}"    "$TMP/$ASSET"
  fetch "${urlbase}/SHA256SUMS"  "$TMP/SHA256SUMS"
  verify "$TMP/$ASSET" "$TMP/SHA256SUMS" "$ASSET"
fi

# --- install binary ----------------------------------------------------------
info "installing binary -> ${BIN_DIR}/dbagent"
run install -d "$BIN_DIR"
run install -m 0755 "$TMP/$ASSET" "${BIN_DIR}/dbagent"

# --- config ------------------------------------------------------------------
run install -d -m 0755 "$CONF_DIR"
CONF="${CONF_DIR}/agent.toml"
if run test -f "$CONF"; then
  info "keeping existing ${CONF}"
else
  API_KEY="${DBAGENT_API_KEY:-}"
  # On-site self-registration: with a partner signup code and no key, register a fresh
  # tenant and receive its ingest key — no pre-provisioning needed.
  if [ -z "$API_KEY" ] && [ -n "${DBAGENT_SIGNUP_CODE:-}" ]; then
    REGISTER_URL="${DBAGENT_REGISTER_URL:-$(printf '%s' "$INGEST_URL" | sed 's#/ingest#/register#')}"
    HN="$(hostname 2>/dev/null || echo server)"
    info "registering with signup code at ${REGISTER_URL}"
    _resp="$(curl -fsSL -X POST "$REGISTER_URL" -H 'Content-Type: application/json' \
      -d "{\"code\":\"${DBAGENT_SIGNUP_CODE}\",\"company\":\"${DBAGENT_COMPANY:-$HN}\",\"email\":\"${DBAGENT_EMAIL:-}\",\"hostname\":\"$HN\"}" 2>/dev/null || true)"
    API_KEY="$(printf '%s' "$_resp" | sed -n 's/.*"api_key"[ ]*:[ ]*"\(dbk_[^"]*\)".*/\1/p')"
    if [ -n "$API_KEY" ]; then info "registered — ingest key received"; else warn "registration failed; will prompt for a key"; fi
  fi
  if [ -z "$API_KEY" ]; then
    API_KEY="$(ask "Paste the API key we issued you (dbk_…), or press Enter to set it later: ")"
  fi
  [ -n "$API_KEY" ] || API_KEY="dbk_CHANGE_ME"
  tmpconf="$TMP/agent.toml"
  cat >"$tmpconf" <<EOF
# dbagent configuration — written by install.sh. The agent reads ONLY from your
# SQL Server and pushes results to DBMonitor. Your DB credentials never leave here.

[source]
server   = "localhost"
port     = 1433
database = "master"
user     = "dbmonitor_ro"
password = "CHANGE_ME"
encrypt  = "true"

[ingest]
url     = "${INGEST_URL}"
api_key = "${API_KEY}"

[agent]
interval_minutes = 15
EOF
  run install -m 0600 "$tmpconf" "$CONF"
  info "wrote ${CONF} (mode 0600)"
  [ "$API_KEY" = "dbk_CHANGE_ME" ] && warn "no API key set — edit ${CONF} before starting"
fi

# --- systemd service ---------------------------------------------------------
if [ "${DBAGENT_NO_SERVICE:-0}" = "1" ] || ! command -v systemctl >/dev/null 2>&1; then
  warn "skipping systemd service (DBAGENT_NO_SERVICE set or systemctl absent)"
else
  info "installing systemd unit -> ${UNIT_PATH}"
  unit="$TMP/${SERVICE_NAME}.service"
  cat >"$unit" <<EOF
[Unit]
Description=DBMonitor local collector agent
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=${BIN_DIR}/dbagent --config ${CONF}
Restart=on-failure
RestartSec=30
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
ReadOnlyPaths=${CONF_DIR}

[Install]
WantedBy=multi-user.target
EOF
  run install -m 0644 "$unit" "$UNIT_PATH"
  run systemctl daemon-reload
fi

# --- next steps --------------------------------------------------------------
DB_NEEDS_EDIT=1
run grep -q 'password = "CHANGE_ME"' "$CONF" 2>/dev/null || DB_NEEDS_EDIT=0

printf '\n%sdbagent installed.%s\n\n' "$B" "$N"
if [ "$DB_NEEDS_EDIT" = "1" ]; then
  cat <<EOF
Next:
  1. Configure your SQL Server connection. Either:
       ${B}sudo ${BIN_DIR}/dbagent --setup${N}        # browser UI on http://localhost:7070
     or edit ${B}${CONF}${N} directly (set [source] + api_key).
  2. Test one collection:
       ${B}sudo ${BIN_DIR}/dbagent --config ${CONF} --once${N}
  3. Start the service:
       ${B}sudo systemctl enable --now ${SERVICE_NAME}${N}
       ${B}journalctl -u ${SERVICE_NAME} -f${N}
EOF
else
  cat <<EOF
Config looks complete. Start it:
  ${B}sudo systemctl enable --now ${SERVICE_NAME}${N}
  ${B}journalctl -u ${SERVICE_NAME} -f${N}
EOF
fi
