#!/usr/bin/env bash
set -Eeuo pipefail
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Packaging replaces this token before inventorying and signing the script.
bootstrap_version='0.2.60'

bootstrap_vm() (
  set -Eeuo pipefail
  umask 077
  fail() { printf '%s\n' "$*" >&2; exit 1; }
  [[ $(id -u) == 0 ]] || fail 'Run this command on your dedicated VM with sudo.'
  [[ $bootstrap_version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || fail 'This source script is not a published installer. Use the script supplied with a signed release.'
  [[ $(uname -m) == x86_64 ]] || fail 'Use an x86-64 VM.'
  # shellcheck disable=SC1091
  . /etc/os-release
  [[ $ID == ubuntu && $VERSION_ID == 24.04 ]] || fail 'Use Ubuntu 24.04.'
  for tool in curl openssl sha256sum tar flock; do command -v "$tool" >/dev/null || fail "Install $tool before running the installer."; done
  workspace=/var/lib/software-house-installer
  for ((i=1; i<=$#; i++)); do
    if [[ ${!i} == --workspace ]]; then
      i=$((i+1)); workspace=${!i:-}
    fi
  done
  [[ $workspace =~ ^/[a-zA-Z0-9/_.-]+$ && $workspace != *'/../'* && $workspace != */.. ]] || fail 'Use an absolute protected workspace path.'
  safe_directory() {
    local candidate=$1 current=$1
    while [[ $current != / ]]; do
      [[ ! -L $current ]] || fail "Refusing a symlink: $current"
      if [[ -e $current ]]; then
        [[ -d $current && $(stat -c %u "$current") == 0 ]] || fail "Unsafe directory: $current"
        (( (8#$(stat -c %a "$current") & 8#022) == 0 )) || fail "Writable directory: $current"
      fi
      current=$(dirname "$current")
    done
    # Parent ownership and write permissions are checked above; only the leaf needs 0700.
    # shellcheck disable=SC2174
    mkdir -p -m 0700 "$candidate"
  }
  safe_directory "$workspace"
  [[ $(stat -c %a "$workspace") == 700 ]] || fail 'The workspace must have mode 0700.'
  safe_directory "$workspace/bootstrap"
  exec 9>"$workspace/bootstrap/download.lock"
  flock -n 9 || fail 'Another installer download is running. Wait for it to finish.'
  version_file="$workspace/bootstrap/version"
  if [[ -e $version_file || -L $version_file ]]; then
    [[ -f $version_file && ! -L $version_file && $(stat -c '%u:%a:%h' "$version_file") == 0:600:1 ]] || fail 'Unsafe retained release identity.'
    bootstrap_version=$(cat "$version_file")
    [[ $bootstrap_version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || fail 'Invalid retained release version.'
  else
    printf '%s\n' "$bootstrap_version" > "$version_file"
  fi
  safe_directory /opt/software-house/releases
  release_dir="/opt/software-house/releases/$bootstrap_version"
  if [[ ! -e $release_dir && ! -L $release_dir ]]; then
    download=$(mktemp -d "$workspace/bootstrap/download.XXXXXXXX")
    extracted=$(mktemp -d /opt/software-house/releases/.extract.XXXXXXXX)
    trap 'rm -rf -- "$download" "$extracted"' EXIT
    release_url="https://downloads.blazingbanana.com/software-house/portable/versions/$bootstrap_version"
    archive=software-house-online-linux-x64.tar.gz
    printf 'Downloading Software House %s…\n' "$bootstrap_version"
    for asset in "$archive" "$archive.sha256" "$archive.sha256.sig" software-house-release-public.pem; do
      curl --proto '=https' --proto-redir '=https' --fail --show-error --location --retry 5 --connect-timeout 20 --max-time 1800 --output "$download/$asset" "$release_url/$asset"
    done
    (
      cd "$download"
      openssl pkey -pubin -in software-house-release-public.pem -pubout -out public.canonical.pem
      printf '%s  %s\n' 42ad9f615d71847e5428e6db66ad1d59656968745b46e31d6c098f77b8f6e72d public.canonical.pem | sha256sum --check --status
      openssl pkeyutl -verify -pubin -rawin -inkey public.canonical.pem -in "$archive.sha256" -sigfile "$archive.sha256.sig"
      # Accept exactly the expected filename, never paths from a checksum file.
      expected=$(sha256sum "$archive")
      [[ $(cat "$archive.sha256") == "$expected" ]] || fail 'Release archive checksum mismatch.'
      tar --no-same-owner --same-permissions -xzf "$archive" -C "$extracted"
    )
    [[ -f $extracted/.portable/installer.mjs && -x $extracted/.portable/bin/node ]] || fail 'The verified archive has no installer runtime.'
    "$extracted/.portable/bin/node" --input-type=module -e 'import fs from "node:fs"; const m=JSON.parse(fs.readFileSync(process.argv[1])); if(m.kind!=="portable" || m.vmInstaller!==true || m.version!==process.argv[2]) process.exit(1)' "$extracted/portable-release.json" "$bootstrap_version" || fail 'The signed package does not match this VM installer release.'
    mv -T "$extracted" "$release_dir"
    rm -rf -- "$download"
    trap - EXIT
  fi
  safe_directory "$release_dir"
  [[ -f $release_dir/install.sh && ! -L $release_dir/install.sh ]] || fail 'The retained release is incomplete.'
  printf 'Using Software House %s. Installation state: %s\n' "$bootstrap_version" "$workspace"
  # Release files are checked against their signed inventory by the engine.
  flock -u 9
  exec bash "$release_dir/install.sh" "$@"
)

if [[ ${1:-} == --domain ]]; then set -- kubernetes "$@"; fi

case "${1:-}" in
  ''|--help|-h)
    printf '%s\n' 'Software House Kubernetes installation' \
      'sudo bash install.sh --domain house.example.com' \
      './install.sh kubernetes --domain house.example.com [--owner-email EMAIL --dedicated]' \
      './install.sh cloud --config /protected/house/cloud.json --plan|--apply' \
      './install.sh kubernetes --config /protected/house/manifest.json' \
      './install.sh kubernetes --config /protected/house/manifest.json --restore-release-backup UUID --release-version VERSION --confirm-restore DOMAIN' \
      './install.sh kubernetes --migration-wizard --migration-kit /protected/migration/migration-kit.json' \
      './install.sh kubernetes --config /protected/source/manifest.json --migration-ui' \
      './install.sh kubernetes --migration-ui --migration-kit /protected/migration/migration-kit.json' \
      './install.sh kubernetes --config /protected/source/manifest.json --migration-backup' \
      './install.sh kubernetes --config SOURCE --resume-migration-source --destination-config DESTINATION --accept-old-data DOMAIN' \
      './install.sh kubernetes --config /protected/source/manifest.json --revoke-migration-access' \
      './install.sh kubernetes --config /protected/source/manifest.json --renew-migration-access /protected/pack/source-access.json' \
      './install.sh kubernetes --config /protected/manifest.json --prepare-update-permissions' \
      './install.sh kubernetes --config /protected/target/manifest.json --restore /protected/source/state/migration.json' \
      './install.sh kubernetes --config /protected/target/manifest.json --activate-migration'
    exit 0 ;;
  kubernetes|cloud) ;;
  *) printf '%s\n' 'Select cloud or kubernetes. See ./install.sh --help.' >&2; exit 2 ;;
esac

# Signed packages and developer checkouts share the validation/evidence engine.
if [ -f "$script_dir/.portable/installer.mjs" ]; then
  export PATH="$script_dir/.portable/bin:$PATH"
  if [ "$1" = kubernetes ]; then shift; fi
  exec "$script_dir/.portable/bin/node" "$script_dir/.portable/installer.mjs" "$@"
fi
if [[ ! -f $script_dir/infra/agent-install.mjs ]]; then
  [[ $1 == kubernetes && " $* " == *' --domain '* ]] || { printf '%s\n' 'The downloaded script installs a dedicated VM. Use --domain DOMAIN, or extract a verified package for --config and cloud operations.' >&2; exit 2; }
  bootstrap_vm "$@"
  exit $?
fi
exec npm --prefix "$script_dir" run --silent agent:install -- "$@"
