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

release_url="${RELAYPBX_RELEASE_URL:-https://downloads.relaypbx.com/stable/relaypbx-latest.tar.gz}"
release_file=""
expected_sha256=""
domain=""
public_ip=""
claim_code=""
install_dir="/opt/relaypbx"
preflight_only=false

usage() {
  cat <<'EOF'
RelayPBX production bootstrap

Usage:
  sudo ./install-relaypbx.sh --domain pbx.example.com --public-ip 203.0.113.10 [options]

Options:
  --claim-code CODE       One-time claim from the customer portal; omit for Community.
  --release-url URL       HTTPS release bundle URL.
  --release-file PATH     Local release bundle (for offline/acceptance testing).
  --sha256 HEX            Expected SHA-256 (otherwise fetched from URL.sha256).
  --install-dir PATH      Default: /opt/relaypbx.
  --preflight-only        Validate prerequisites without installing.
  --help                  Show this help.
EOF
}

while (($#)); do
  case "$1" in
    --domain) domain="${2:-}"; shift 2 ;;
    --public-ip) public_ip="${2:-}"; shift 2 ;;
    --claim-code) claim_code="${2:-}"; shift 2 ;;
    --release-url) release_url="${2:-}"; shift 2 ;;
    --release-file) release_file="${2:-}"; shift 2 ;;
    --sha256) expected_sha256="${2:-}"; shift 2 ;;
    --install-dir) install_dir="${2:-}"; shift 2 ;;
    --preflight-only) preflight_only=true; shift ;;
    --help) usage; exit 0 ;;
    *) usage >&2; exit 2 ;;
  esac
done

[[ "$EUID" -eq 0 ]] || { printf '%s\n' "Run the installer with sudo." >&2; exit 1; }
[[ -n "$domain" && -n "$public_ip" ]] || { usage >&2; exit 2; }

if [[ ! -r /etc/os-release ]]; then
  printf '%s\n' "Cannot identify the operating system." >&2
  exit 1
fi
# shellcheck disable=SC1091
source /etc/os-release
case "${ID:-}:${VERSION_ID:-}" in
  debian:12|ubuntu:24.04) ;;
  *) printf '%s\n' "Supported systems are Debian 12 and Ubuntu Server 24.04 LTS." >&2; exit 1 ;;
esac

export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y ca-certificates curl gawk iproute2 openssl python3 tar

if ! command -v docker >/dev/null 2>&1; then
  install -m 0755 -d /etc/apt/keyrings
  curl -fsSL "https://download.docker.com/linux/$ID/gpg" -o /etc/apt/keyrings/docker.asc
  chmod a+r /etc/apt/keyrings/docker.asc
  arch=$(dpkg --print-architecture)
  codename="${VERSION_CODENAME:?OS codename is unavailable}"
  printf 'deb [arch=%s signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/%s %s stable\n' \
    "$arch" "$ID" "$codename" > /etc/apt/sources.list.d/docker.list
  apt-get update
  apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
  systemctl enable --now docker
fi

temporary=$(mktemp -d)
trap 'rm -rf "$temporary"' EXIT
bundle="$temporary/relaypbx-release.tar.gz"

if [[ -n "$release_file" ]]; then
  cp "$release_file" "$bundle"
else
  case "$release_url" in
    https://*) ;;
    *) printf '%s\n' "Remote release downloads must use HTTPS." >&2; exit 2 ;;
  esac
  if [[ -z "$expected_sha256" ]]; then
    expected_sha256=$(curl --fail --location --silent --show-error \
      --proto '=https' --tlsv1.2 \
      "${release_url}.sha256" | awk 'NR==1 { print $1 }')
  fi
  [[ "$expected_sha256" =~ ^[a-fA-F0-9]{64}$ ]] || {
    printf '%s\n' "The published release checksum is missing or invalid." >&2
    exit 2
  }
  curl --fail --location --silent --show-error \
    --proto '=https' --tlsv1.2 \
    --output "$bundle" "$release_url"
fi

actual_sha256=$(sha256sum "$bundle" | awk '{print $1}')
if [[ -n "$expected_sha256" && "${actual_sha256,,}" != "${expected_sha256,,}" ]]; then
  printf '%s\n' "Release checksum verification failed." >&2
  exit 3
fi

while IFS= read -r entry; do
  if [[ "$entry" == /* || "$entry" == *".."* ]]; then
    printf 'Unsafe archive path: %s\n' "$entry" >&2
    exit 3
  fi
done < <(tar -tzf "$bundle")

tar -xzf "$bundle" -C "$temporary"
[[ -f "$temporary/deploy/install/install.sh" ]] || {
  printf '%s\n' "The release bundle is incomplete." >&2
  exit 3
}
chmod +x "$temporary/deploy/install/"*.sh

arguments=(
  --domain "$domain"
  --public-ip "$public_ip"
  --install-dir "$install_dir"
)
[[ -n "$claim_code" ]] && arguments+=(--claim-code "$claim_code")
[[ "$preflight_only" == true ]] && arguments+=(--preflight-only)

exec bash "$temporary/deploy/install/install.sh" "${arguments[@]}"
