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

package_version="1.13.4-gpc.28"
installer_revision="2026.09.10.1"
release_tag="livekit-node-v${package_version}"
package_name="GPC-LiveKit-Node-${package_version}-linux-amd64"
archive_name="${package_name}.tar.gz"
mirror_release_url="https://api.gpcchat.com/releases/livekit-node/${package_version}/${archive_name}"
github_release_url="https://github.com/gpcchat/gpcwallet-releases/releases/download/${release_tag}/${archive_name}"
package_sha256="12677d2dbd36f27c4f4a1e446ed08f45acb73f273166f3e9756cdc55f1d5c40d"
cache_dir="${GPC_LIVEKIT_NODE_CACHE_DIR:-}"

usage() {
  cat <<'EOF'
Usage:
  ./install-livekit-node-on-server.sh [options]

Options:
  --main-api URL       Main API base URL (default: https://api.gpcchat.com)
  --public-ip IP       Node public IP (default: auto-detect)
  --region REGION      Routing region (default: global)
  --capacity NUMBER    Maximum active rooms (default: 100)
  --acme-email EMAIL   Let's Encrypt contact (default: admin@gpcchat.com)
  --replace-node ID    Replace a drained node while preserving its identity
  --wallet-key-file FILE
                       Original node wallet key (required with --replace-node)
  --skip-firewall      Do not add rules when UFW is active
  --version            Print installer and package versions
  --print-checksum     Print the pinned package SHA-256
  -h, --help           Show this help

Run this script directly on a fresh Ubuntu/Debian linux-amd64 server. It
downloads the pinned native node package, verifies SHA-256, and runs the
bundled installer. Docker, Redis, PostgreSQL, and a repository checkout are
not required. The verified package is cached and reused on later runs. Set
GPC_LIVEKIT_NODE_CACHE_DIR to override the cache directory.

Use this script for a new node or a controlled server replacement. To update
an existing node in place, use upgrade.sh from the verified release package.
EOF
}

fatal() {
  echo "install-livekit-node-on-server: $*" >&2
  exit 1
}

if [[ "$#" -eq 1 ]]; then
  case "$1" in
    -h|--help)
      usage
      exit 0
      ;;
    --version)
      printf 'GPC node installer %s (package %s)\n' "$installer_revision" "$package_version"
      exit 0
      ;;
    --print-checksum)
      printf '%s  %s\n' "$package_sha256" "$archive_name"
      exit 0
      ;;
  esac
fi

[[ "$(uname -s)" == "Linux" ]] || fatal "Linux is required"
case "$(uname -m)" in
  x86_64|amd64) ;;
  *) fatal "only linux-amd64 is currently supported" ;;
esac

command -v curl >/dev/null 2>&1 || fatal "curl is required"
command -v tar >/dev/null 2>&1 || fatal "tar is required"
if [[ "$EUID" -ne 0 ]]; then
  command -v sudo >/dev/null 2>&1 || fatal "run as root or install sudo"
fi

if [[ -z "$cache_dir" ]]; then
  if [[ "$EUID" -eq 0 ]]; then
    cache_dir="/var/cache/gpc-livekit-node"
  else
    cache_dir="/var/tmp/gpc-livekit-node-cache-${UID}"
  fi
fi
mkdir -p "$cache_dir"
chmod 0700 "$cache_dir"

work_dir="$(mktemp -d "${TMPDIR:-/tmp}/gpc-livekit-server-install.XXXXXX")"
archive_path="${cache_dir}/${archive_name}"
partial_archive_path="${archive_path}.part"
extract_dir="${work_dir}/extract"

cleanup() {
  if [[ -d "$work_dir" ]]; then
    find "$work_dir" -depth -mindepth 1 -delete 2>/dev/null || true
    rmdir "$work_dir" 2>/dev/null || true
  fi
}
trap cleanup EXIT

sha256_file() {
  if command -v sha256sum >/dev/null 2>&1; then
    sha256sum "$1" | awk '{print $1}'
    return
  fi
  if command -v shasum >/dev/null 2>&1; then
    shasum -a 256 "$1" | awk '{print $1}'
    return
  fi
  fatal "sha256sum or shasum is required"
}

package_ready=false
if [[ -f "$archive_path" ]]; then
  actual_sha256="$(sha256_file "$archive_path")"
  if [[ "$actual_sha256" == "$package_sha256" ]]; then
    package_ready=true
    echo "Using cached GPC LiveKit Node ${package_version}: ${archive_path}"
  else
    echo "Discarding cached package with an invalid checksum." >&2
    unlink "$archive_path"
  fi
fi

if [[ "$package_ready" != "true" ]]; then
  if [[ -f "$partial_archive_path" ]] \
    && [[ "$(sha256_file "$partial_archive_path")" == "$package_sha256" ]]; then
    mv "$partial_archive_path" "$archive_path"
    package_ready=true
    echo "Recovered completed package from the download cache."
  fi
fi

if [[ "$package_ready" != "true" ]]; then
  if [[ -s "$partial_archive_path" ]]; then
    echo "Resuming GPC LiveKit Node ${package_version} download..."
  else
    echo "Downloading GPC LiveKit Node ${package_version}..."
  fi
  download_succeeded=false
  for release_url in "$mirror_release_url" "$github_release_url"; do
    echo "Trying ${release_url}"
    if curl -fL --retry 3 --retry-delay 2 --retry-all-errors \
      --connect-timeout 15 --continue-at - \
      -o "$partial_archive_path" \
      "$release_url"; then
      download_succeeded=true
      break
    fi
    echo "Download source failed; trying the next source." >&2
  done
  if [[ "$download_succeeded" != "true" ]]; then
    fatal "download interrupted; run the same command again to resume it"
  fi

  actual_sha256="$(sha256_file "$partial_archive_path")"
  if [[ "$actual_sha256" != "$package_sha256" ]]; then
    unlink "$partial_archive_path"
    fatal "package checksum mismatch: expected ${package_sha256}, got ${actual_sha256}"
  fi
  mv "$partial_archive_path" "$archive_path"
fi

actual_sha256="$(sha256_file "$archive_path")"
[[ "$actual_sha256" == "$package_sha256" ]] \
  || fatal "package checksum mismatch: expected ${package_sha256}, got ${actual_sha256}"

while IFS= read -r archive_member; do
  normalized_member="${archive_member#./}"
  case "$normalized_member" in
    "$package_name"|"${package_name}/"*) ;;
    *) fatal "package contains an unexpected path: ${archive_member}" ;;
  esac
  case "/$normalized_member/" in
    *"/../"*) fatal "package contains an unsafe path: ${archive_member}" ;;
  esac
done < <(tar -tzf "$archive_path")

mkdir -m 0700 "$extract_dir"
tar -xzf "$archive_path" -C "$extract_dir"
installer="${extract_dir}/${package_name}/install.sh"
[[ -f "$installer" && ! -L "$installer" && -x "$installer" ]] \
  || fatal "the downloaded package does not contain a regular executable install.sh"

echo "Package verified. Installing the native node..."
if [[ "$EUID" -eq 0 ]]; then
  "$installer" "$@"
else
  sudo "$installer" "$@"
fi

node_cli="$(command -v gpc-livekit-node 2>/dev/null || true)"
[[ -n "$node_cli" && -x "$node_cli" ]] || fatal "installation completed without the gpc-livekit-node command"
installed_version="$($node_cli version | head -n 1)"
[[ "$installed_version" == *"${package_version}"* ]] \
  || fatal "installed version differs: ${installed_version}"

echo "GPC LiveKit Node ${package_version} installation completed."
