#!/bin/sh
# Hopbits Linux & Docker Node Installer — https://hopbits.io/install.sh
#
# Quick start (prints an 8-character pairing code for https://hopbits.io/dashboard):
#   curl -fsSL https://hopbits.io/install.sh | sudo sh
#
# Headless auto-enrolment (using a 24h token from https://hopbits.io/dashboard):
#   curl -fsSL https://hopbits.io/install.sh | HOPBITS_ENROLL="<token>" sudo -E sh
#
# Optional overrides:
#   HOPBITS_NETWORK_MODE=host|bridge   (default: host)
#   HOPBITS_DAILY_MB=200               (optional lower daily traffic cap in MB)
#   HOPBITS_IMAGE=<image>              (override container image)
#   HOPBITS_GATEWAY=<wss-url>          (override gateway endpoint)

set -eu

CONTAINER_NAME="${HOPBITS_CONTAINER_NAME:-hopbits-agent}"
VOLUME_NAME="${HOPBITS_VOLUME_NAME:-hopbits-data}"
NET_MODE="${HOPBITS_NETWORK_MODE:-host}"
RELEASE_BASE="${HOPBITS_RELEASE_BASE:-https://hopbits.io/releases}"
ENV_DIR="/etc/hopbits"
ENV_FILE="${ENV_DIR}/agent.env"

say() {
  printf '==> %s\n' "$*"
}

err() {
  printf 'error: %s\n' "$*" >&2
  exit 1
}

fetch_file() {
  url="$1"
  dest="$2"
  if command -v curl >/dev/null 2>&1; then
    curl -fsSL "$url" -o "$dest"
  elif command -v wget >/dev/null 2>&1; then
    wget -qO "$dest" "$url"
  else
    err "Neither curl nor wget is installed."
  fi
}

verify_sha256() {
  dir="$1"
  bin_name="$2"
  expected="$(awk -v f="$bin_name" '$2 == f || $2 == "*"f { print $1; exit }' "${dir}/SHA256SUMS")"
  if [ -z "$expected" ]; then
    err "Could not find SHA-256 entry for ${bin_name} in SHA256SUMS."
  fi
  if command -v sha256sum >/dev/null 2>&1; then
    actual="$(sha256sum "${dir}/${bin_name}" | awk '{ print $1 }')"
  elif command -v shasum >/dev/null 2>&1; then
    actual="$(shasum -a 256 "${dir}/${bin_name}" | awk '{ print $1 }')"
  else
    err "Neither sha256sum nor shasum is installed to verify the agent binary."
  fi
  if [ "$actual" != "$expected" ]; then
    err "SHA-256 mismatch for ${bin_name} (expected ${expected}, got ${actual})."
  fi
}

if ! command -v docker >/dev/null 2>&1; then
  err "Docker is not installed. Install Docker Engine first (curl -fsSL https://get.docker.com | sudo sh) and re-run."
fi

DOCKER="docker"
if ! docker info >/dev/null 2>&1; then
  if command -v sudo >/dev/null 2>&1 && sudo -n docker info >/dev/null 2>&1; then
    DOCKER="sudo docker"
  else
    err "Cannot connect to the Docker daemon. Re-run with sudo (curl -fsSL https://hopbits.io/install.sh | sudo sh) or start docker.service."
  fi
fi

case "${NET_MODE}" in
  host|bridge) ;;
  *) err "HOPBITS_NETWORK_MODE must be 'host' or 'bridge' (got '${NET_MODE}')." ;;
esac

build_from_release_binary() {
  raw_arch="$(uname -m)"
  case "${raw_arch}" in
    x86_64|amd64) ARCH="amd64" ;;
    aarch64|arm64) ARCH="arm64" ;;
    *) err "Unsupported CPU architecture '${raw_arch}' (supported: x86_64/amd64, aarch64/arm64)." ;;
  esac

  BIN_NAME="hopbits-agent-linux-${ARCH}"
  TMP_BUILD="$(mktemp -d)"

  say "Downloading verified ${BIN_NAME} from ${RELEASE_BASE}..."
  if ! fetch_file "${RELEASE_BASE}/SHA256SUMS" "${TMP_BUILD}/SHA256SUMS" || \
     ! fetch_file "${RELEASE_BASE}/${BIN_NAME}" "${TMP_BUILD}/${BIN_NAME}"; then
    rm -rf "${TMP_BUILD}"
    err "Could not download ${BIN_NAME} from ${RELEASE_BASE}. Check outbound HTTPS connectivity."
  fi

  verify_sha256 "${TMP_BUILD}" "${BIN_NAME}"
  mv "${TMP_BUILD}/${BIN_NAME}" "${TMP_BUILD}/hopbits-agent"
  chmod 0755 "${TMP_BUILD}/hopbits-agent"

  mkdir -p "${TMP_BUILD}/data"
  chmod 0700 "${TMP_BUILD}/data"
  if [ "$(id -u)" = "0" ]; then
    chown 65532:65532 "${TMP_BUILD}/data" 2>/dev/null || true
  fi

  cat > "${TMP_BUILD}/Dockerfile" <<'EOF'
FROM gcr.io/distroless/static-debian12:nonroot
COPY hopbits-agent /hopbits-agent
COPY --chown=65532:65532 data /var/lib/hopbits
VOLUME ["/var/lib/hopbits"]
USER 65532:65532
ENTRYPOINT ["/hopbits-agent"]
EOF

  say "Building hardened local container image (hopbits/agent:local)..."
  if ! ${DOCKER} build -q -t hopbits/agent:local "${TMP_BUILD}" >/dev/null; then
    rm -rf "${TMP_BUILD}"
    err "Failed to build hopbits/agent:local (check access to gcr.io/distroless/static-debian12:nonroot)."
  fi
  rm -rf "${TMP_BUILD}"
  IMAGE="hopbits/agent:local"
}

pull_or_build_image() {
  if [ -n "${HOPBITS_IMAGE:-}" ]; then
    say "Pulling ${HOPBITS_IMAGE}..."
    ${DOCKER} pull "${HOPBITS_IMAGE}" >/dev/null
    IMAGE="${HOPBITS_IMAGE}"
    return 0
  fi

  build_from_release_binary
}

IMAGE=""
pull_or_build_image
say "Using image: ${IMAGE}"

ENV_ARGS=""
if [ -n "${HOPBITS_ENROLL:-}" ] || [ -n "${HOPBITS_DAILY_MB:-}" ] || [ -n "${HOPBITS_GATEWAY:-}" ] || [ -n "${HOPBITS_DISABLE_KINDS:-}" ] || [ -n "${HOPBITS_AUTO_UPDATE:-}" ] || [ -n "${HOPBITS_LOG_LEVEL:-}" ]; then
  umask 077
  mkdir -p "${ENV_DIR}"
  chmod 0700 "${ENV_DIR}"
  : > "${ENV_FILE}"
  chmod 0600 "${ENV_FILE}"
  if [ -n "${HOPBITS_ENROLL:-}" ]; then
    printf 'HOPBITS_ENROLL=%s\n' "${HOPBITS_ENROLL}" >> "${ENV_FILE}"
  fi
  if [ -n "${HOPBITS_DAILY_MB:-}" ]; then
    printf 'HOPBITS_DAILY_MB=%s\n' "${HOPBITS_DAILY_MB}" >> "${ENV_FILE}"
  fi
  if [ -n "${HOPBITS_GATEWAY:-}" ]; then
    printf 'HOPBITS_GATEWAY=%s\n' "${HOPBITS_GATEWAY}" >> "${ENV_FILE}"
  fi
  if [ -n "${HOPBITS_DISABLE_KINDS:-}" ]; then
    printf 'HOPBITS_DISABLE_KINDS=%s\n' "${HOPBITS_DISABLE_KINDS}" >> "${ENV_FILE}"
  fi
  if [ -n "${HOPBITS_AUTO_UPDATE:-}" ]; then
    printf 'HOPBITS_AUTO_UPDATE=%s\n' "${HOPBITS_AUTO_UPDATE}" >> "${ENV_FILE}"
  fi
  if [ -n "${HOPBITS_LOG_LEVEL:-}" ]; then
    printf 'HOPBITS_LOG_LEVEL=%s\n' "${HOPBITS_LOG_LEVEL}" >> "${ENV_FILE}"
  fi
  ENV_ARGS="--env-file ${ENV_FILE}"
fi

${DOCKER} volume create "${VOLUME_NAME}" >/dev/null
${DOCKER} rm -f "${CONTAINER_NAME}" >/dev/null 2>&1 || true

say "Starting ${CONTAINER_NAME} (--network ${NET_MODE}, --cap-drop ALL, UID 65532)..."
if [ "${NET_MODE}" = "bridge" ]; then
  # shellcheck disable=SC2086
  ${DOCKER} run -d \
    --name "${CONTAINER_NAME}" \
    --restart=always \
    --cap-drop ALL \
    --security-opt no-new-privileges:true \
    --network bridge \
    --sysctl "net.ipv4.ping_group_range=0 2147483647" \
    -e HOPBITS_NETWORK_MODE=bridge \
    ${ENV_ARGS} \
    -v "${VOLUME_NAME}:/var/lib/hopbits" \
    "${IMAGE}" >/dev/null
else
  # shellcheck disable=SC2086
  ${DOCKER} run -d \
    --name "${CONTAINER_NAME}" \
    --restart=always \
    --cap-drop ALL \
    --security-opt no-new-privileges:true \
    --network host \
    -e HOPBITS_NETWORK_MODE=host \
    ${ENV_ARGS} \
    -v "${VOLUME_NAME}:/var/lib/hopbits" \
    "${IMAGE}" >/dev/null
fi

say "Hopbits node container '${CONTAINER_NAME}' is running!"
if [ -n "${HOPBITS_ENROLL:-}" ]; then
  printf '\nAuto-enrolment token configured in %s (mode 0600).\n' "${ENV_FILE}"
  printf 'Verify your node online at: https://hopbits.io/dashboard\n'
  printf 'Follow live logs anytime:   sudo docker logs -f %s\n\n' "${CONTAINER_NAME}"
else
  # Wait up to 6 seconds for self-tests + gateway handshake to print PAIRING CODE
  i=0
  while [ "$i" -lt 6 ]; do
    sleep 1
    if ${DOCKER} logs "${CONTAINER_NAME}" 2>&1 | grep -q "PAIRING CODE\|node paired"; then
      break
    fi
    i=$((i + 1))
  done
  printf '\n--- Recent node startup logs ---\n'
  ${DOCKER} logs --tail 20 "${CONTAINER_NAME}" 2>&1 || true
  printf -- '--------------------------------\n\n'
  printf 'Next step:\n'
  printf '  1. Copy the 8-character pairing code printed above (or run: sudo docker logs -f %s)\n' "${CONTAINER_NAME}"
  printf '  2. Open https://hopbits.io/dashboard and paste the code under "Pair with 8-character code".\n\n'
fi
