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

readonly REZA_VERSION="1.4.0"
readonly REPOSITORY_ROOT="https://repos.rms.center/reza/${REZA_VERSION}"
readonly MEDIATYPE_URL="${REPOSITORY_ROOT}/assets/reza_mediatype.json"
readonly EXPECTED_PRIMARY_FINGERPRINT="CF61BFCF4DE8DCA103F4B028C1E8D737FD1E84EB"
readonly EXPECTED_SIGNING_FINGERPRINT="8C1D0044607850194FF1F67210B477E99C33039C"

if [[ "${EUID}" -ne 0 ]]; then
  printf 'Run this installer as root, for example: sudo bash install.sh\n' >&2
  exit 1
fi

if [[ ! -r /etc/os-release ]]; then
  printf 'Cannot identify this operating system: /etc/os-release is missing.\n' >&2
  exit 1
fi

# shellcheck disable=SC1091
. /etc/os-release

work_dir=$(mktemp -d)
cleanup() {
  rm -rf -- "$work_dir"
}
trap cleanup EXIT

require_supported_architecture() {
  local architecture=$1
  case "$architecture" in
    amd64|arm64|i386|x86_64|aarch64|i486|i586|i686) ;;
    *)
      printf 'Unsupported package architecture: %s\n' "$architecture" >&2
      exit 1
      ;;
  esac
}

verify_repository_key() {
  local key_file=$1
  local fingerprints primary_fingerprint signing_fingerprint

  fingerprints=$(gpg --batch --show-keys --with-colons \
    --fingerprint --fingerprint "$key_file")
  primary_fingerprint=$(awk -F: '$1 == "fpr" { print $10; exit }' <<<"$fingerprints")
  signing_fingerprint=$(awk -F: '$1 == "fpr" { count++; if (count == 2) { print $10; exit } }' <<<"$fingerprints")

  if [[ "$primary_fingerprint" != "$EXPECTED_PRIMARY_FINGERPRINT" ]]; then
    printf 'Repository primary-key fingerprint mismatch.\n' >&2
    exit 1
  fi
  if [[ "$signing_fingerprint" != "$EXPECTED_SIGNING_FINGERPRINT" ]]; then
    printf 'Repository signing-subkey fingerprint mismatch.\n' >&2
    exit 1
  fi

  printf 'Verified ReZa repository signing key.\n'
}

download_repository_key() {
  local key_file=$1
  curl --fail --silent --show-error --location \
    --output "$key_file" \
    "${REPOSITORY_ROOT}/release/keys/reza-archive-keyring.asc"
  verify_repository_key "$key_file"
}

install_apt_package() {
  case "${ID}:${VERSION_ID}" in
    debian:10|debian:11|debian:12|debian:13|ubuntu:18.04|ubuntu:20.04|ubuntu:22.04|ubuntu:24.04|ubuntu:26.04) ;;
    *)
      printf 'Unsupported Debian or Ubuntu release: %s %s\n' "$ID" "$VERSION_ID" >&2
      exit 1
      ;;
  esac

  apt-get update
  DEBIAN_FRONTEND=noninteractive apt-get install --yes curl ca-certificates gnupg
  require_supported_architecture "$(dpkg --print-architecture)"

  local key_file="${work_dir}/reza-archive-keyring.asc"
  local release_package="reza-release_${REZA_VERSION}-1+${ID}${VERSION_ID}_all.deb"
  local release_file="${work_dir}/${release_package}"
  local release_url="${REPOSITORY_ROOT}/release/${ID}/pool/main/r/reza-release/${release_package}"

  download_repository_key "$key_file"
  curl --fail --silent --show-error --location --output "$release_file" "$release_url"
  dpkg --install "$release_file"
  apt-get update
  DEBIAN_FRONTEND=noninteractive apt-get install --yes reza
}

install_rpm_package() {
  local repository_distribution package_manager architecture major_version

  case "$ID" in
    almalinux) repository_distribution=alma ;;
    centos) repository_distribution=centos ;;
    ol) repository_distribution=oracle ;;
    rhel) repository_distribution=redhat ;;
    rocky) repository_distribution=rocky ;;
    *)
      printf 'Unsupported RPM distribution: %s\n' "$ID" >&2
      exit 1
      ;;
  esac

  major_version=${VERSION_ID%%.*}
  case "$major_version" in
    8|9|10) ;;
    *)
      printf 'Unsupported %s release: %s\n' "$ID" "$VERSION_ID" >&2
      exit 1
      ;;
  esac

  if command -v dnf >/dev/null 2>&1; then
    package_manager=dnf
  elif command -v yum >/dev/null 2>&1; then
    package_manager=yum
  else
    printf 'Neither dnf nor yum is available.\n' >&2
    exit 1
  fi

  "$package_manager" install --assumeyes curl ca-certificates gnupg2
  architecture=$(rpm --eval '%{_arch}')
  require_supported_architecture "$architecture"

  local key_file="${work_dir}/reza-archive-keyring.asc"
  local release_package="reza-release-${REZA_VERSION}-1.${repository_distribution}${major_version}.noarch.rpm"
  local release_file="${work_dir}/${release_package}"
  local release_url="${REPOSITORY_ROOT}/release/${repository_distribution}/${major_version}/noarch/Packages/${release_package}"

  download_repository_key "$key_file"
  rpm --import "$key_file"
  curl --fail --silent --show-error --location --output "$release_file" "$release_url"
  rpm --upgrade --replacepkgs "$release_file"
  "$package_manager" install --assumeyes reza
}

install_opensuse_package() {
  local major_version architecture

  major_version=${VERSION_ID%%.*}
  case "$major_version" in
    15|16) ;;
    *)
      printf 'Unsupported openSUSE release: %s\n' "$VERSION_ID" >&2
      exit 1
      ;;
  esac

  zypper --non-interactive install curl ca-certificates gpg2
  architecture=$(rpm --eval '%{_arch}')
  require_supported_architecture "$architecture"

  local key_file="${work_dir}/reza-archive-keyring.asc"
  local release_package="reza-release-${REZA_VERSION}-1.opensuse${major_version}.noarch.rpm"
  local release_file="${work_dir}/${release_package}"
  local release_url="${REPOSITORY_ROOT}/release/opensuse/${major_version}/noarch/Packages/${release_package}"

  download_repository_key "$key_file"
  rpm --import "$key_file"
  curl --fail --silent --show-error --location --output "$release_file" "$release_url"
  rpm --upgrade --replacepkgs "$release_file"
  zypper --non-interactive refresh
  zypper --non-interactive install reza
}

case "$ID" in
  debian|ubuntu)
    install_apt_package
    ;;
  almalinux|centos|ol|rhel|rocky)
    install_rpm_package
    ;;
  opensuse|opensuse-leap)
    install_opensuse_package
    ;;
  *)
    printf 'Unsupported Linux distribution: %s\n' "$ID" >&2
    exit 1
    ;;
esac

printf '\nReZa %s was installed successfully.\n' "$REZA_VERSION"
printf 'Next, configure /etc/reza/reza.conf and enable reza.service.\n'
printf 'Download the matching Zabbix media type and import it in the frontend:\n'
printf '  %s\n' "$MEDIATYPE_URL"
