#!/bin/sh
set -eu

BASE_URL="https://dl.neomat.it/rebak"
INSTALL_ROOT="/opt/rebak"
NO_SERVICE=0
REQUESTED_VERSION=""

usage() {
  printf 'Usage: install.sh [VERSION] [--prefix PATH] [--no-service]\n'
}

while [ "$#" -gt 0 ]; do
  case "$1" in
    --prefix)
      [ "$#" -ge 2 ] || { usage >&2; exit 2; }
      INSTALL_ROOT="$2"
      shift 2
      ;;
    --no-service)
      NO_SERVICE=1
      shift
      ;;
    --help|-h)
      usage
      exit 0
      ;;
    --*)
      printf 'Unknown option: %s\n' "$1" >&2
      usage >&2
      exit 2
      ;;
    *)
      [ -z "$REQUESTED_VERSION" ] || { printf 'Only one version may be specified.\n' >&2; exit 2; }
      REQUESTED_VERSION="$1"
      shift
      ;;
  esac
done

[ "$(uname -s)" = "Linux" ] || { printf 'ReBak currently supports Linux only.\n' >&2; exit 1; }
[ "$(id -u)" -eq 0 ] || { printf 'Run this installer as root (for example: sudo sh).\n' >&2; exit 1; }
command -v curl >/dev/null || { printf 'curl is required.\n' >&2; exit 1; }
command -v tar >/dev/null || { printf 'tar is required.\n' >&2; exit 1; }

case "$(uname -m)" in
  x86_64|amd64) RID="linux-x64" ;;
  aarch64|arm64) RID="linux-arm64" ;;
  *) printf 'Unsupported architecture: %s\n' "$(uname -m)" >&2; exit 1 ;;
esac

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

if [ -n "$REQUESTED_VERSION" ]; then
  case "$REQUESTED_VERSION" in
    *[!0-9A-Za-z.-]*) printf 'Invalid version: %s\n' "$REQUESTED_VERSION" >&2; exit 2 ;;
  esac
  MANIFEST_URL="$BASE_URL/releases/$REQUESTED_VERSION/manifest.json"
else
  MANIFEST_URL="$BASE_URL/latest.json"
fi

curl --fail --silent --show-error --location "$MANIFEST_URL" -o "$TMP_DIR/manifest.json"

# The release manifest is intentionally generated in a stable, readable shape.
ASSET_BLOCK="$(sed -n "/\"$RID\"[[:space:]]*:/,/^[[:space:]]*}/p" "$TMP_DIR/manifest.json")"
ASSET_URL="$(printf '%s\n' "$ASSET_BLOCK" | sed -n 's/.*"url"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n 1)"
ASSET_SHA256="$(printf '%s\n' "$ASSET_BLOCK" | sed -n 's/.*"sha256"[[:space:]]*:[[:space:]]*"\([a-fA-F0-9]*\)".*/\1/p' | head -n 1)"
VERSION="$(sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$TMP_DIR/manifest.json" | head -n 1)"

[ -n "$VERSION" ] || { printf 'Manifest does not contain a version.\n' >&2; exit 1; }
[ -z "$REQUESTED_VERSION" ] || [ "$VERSION" = "$REQUESTED_VERSION" ] || {
  printf 'Manifest version does not match the requested version.\n' >&2
  exit 1
}
[ -n "$ASSET_URL" ] || { printf 'Manifest does not contain an asset for %s.\n' "$RID" >&2; exit 1; }
[ -n "$ASSET_SHA256" ] || { printf 'Manifest does not contain a checksum for %s.\n' "$RID" >&2; exit 1; }

ARCHIVE="$TMP_DIR/rebak.tar.gz"
curl --fail --silent --show-error --location "$ASSET_URL" -o "$ARCHIVE"

if command -v sha256sum >/dev/null; then
  ACTUAL_SHA256="$(sha256sum "$ARCHIVE" | awk '{print $1}')"
else
  ACTUAL_SHA256="$(shasum -a 256 "$ARCHIVE" | awk '{print $1}')"
fi
[ "$(printf '%s' "$ACTUAL_SHA256" | tr '[:upper:]' '[:lower:]')" = "$(printf '%s' "$ASSET_SHA256" | tr '[:upper:]' '[:lower:]')" ] || {
  printf 'Checksum verification failed.\n' >&2
  exit 1
}

VERSION_DIR="$INSTALL_ROOT/versions/$VERSION"
TEMP_VERSION_DIR="$INSTALL_ROOT/versions/.${VERSION}.tmp.$$"
mkdir -p "$INSTALL_ROOT/versions"
rm -rf "$TEMP_VERSION_DIR"
mkdir -p "$TEMP_VERSION_DIR"
tar -xzf "$ARCHIVE" -C "$TEMP_VERSION_DIR"

chmod +x "$TEMP_VERSION_DIR/rebak" "$TEMP_VERSION_DIR/tools/$RID/restic"
[ -x "$TEMP_VERSION_DIR/rebak" ] || { printf 'Archive does not contain an executable rebak.\n' >&2; exit 1; }
[ -x "$TEMP_VERSION_DIR/tools/$RID/restic" ] || { printf 'Archive does not contain restic for %s.\n' "$RID" >&2; exit 1; }

rm -rf "$VERSION_DIR"
mv "$TEMP_VERSION_DIR" "$VERSION_DIR"
ln -sfn "$VERSION_DIR" "$INSTALL_ROOT/current"
mkdir -p /usr/local/bin
ln -sfn "$INSTALL_ROOT/current/rebak" /usr/local/bin/rebak

if [ "$NO_SERVICE" -eq 0 ] && command -v systemctl >/dev/null; then
  "$INSTALL_ROOT/current/rebak" agent install
fi

printf 'Installed ReBak %s for %s in %s\n' "$VERSION" "$RID" "$INSTALL_ROOT"
