#!/bin/bash
# ------------------------------------------------------------------------------
# This script will check the available nodejs, if any, and if not compatible or
# none, offer to install a compatible version for this user only (it does not
# change any system-managed version of nodejs).
#
# There is a default recommended version for Reactor. If you want to install a
# specific version (which may not be recommended or compatible), you can add
# -V <m.n.p> to the script command line. The script will attempt to download the
# specified version. Alternately, you can pre-download the nodejs bundle you
# want to use from https://nodejs.org/dist and then use the -N <path> command
# line option to point this script to your downloaded package file.
#
# Use the -U option to have this script unconditionally install for the
# current user, even if the current found version is compatible.
# ------------------------------------------------------------------------------

MYVER=26213

# 64-bit OS assumed to start...
NODEVER="24.18.1"	# if we install nodejs, this version (LTS as of 2025-05-06)
NODERV=2418			# minimum recommended
NODENV=2000			# minimum compatible (known working)
MAXRV=2604			# max known working

# Functions
askyn() {
	local __ans
	local __resultvar
	__resultvar="${1:-ans}"
	while true; do
		echo -e -n "${2:-}"
		read __ans
		case "$__ans" in
			[Yy]* )
				eval "${__resultvar}=Y"
				break
				;;
			[Nn]* )
				eval "${__resultvar}=N"
				break
				;;
		esac
		echo "Please answer Y or N."
	done
}

function die {
	echo -e "$*"
	exit 255
}

function usage {
	cat <<USAGE

Usage: $0 [options]
	-V <m.n.p>                  Install a specific nodejs version
	-P <nodejs-download-file>   Install nodejs from nodejs package
	-U                          Unconditional (force) install

Installs for the current user only; it does not modify any system version.
You may specify -V or -N, but not both. If you omit both, the current
recommended version is offered (typical).
USAGE
	exit 255
}

# Check system architecture; adjust compatible version if needed.
ARCH=$(uname -m)
TAG=${ARCH}
case "$ARCH" in
	x86_64|amd64)
		# Intel 64-bit, remap to x64
		TAG=x64
		;;
	arm64|aarch64)
		TAG=arm64
		;;
	ppc64le|s390x)
		# OK, keep TAG as set
		;;
	arm|armhf|armv7l)
		TAG=armv7l
		echo <<ARMW

***** WARNING - 32-BIT OS *****
Current releases of Reactor are best on 64-bit systems. You are running
a 32-bit OS. Releases of Reactor after April 30 2027 will not operate
on your installed OS because compatible builds of nodejs are no longer
produced beyond v22, which will go End of Life after that date. Please
consider updating your hardware and OS to 64-bit.
ARMW
		NODEVER="22.23.2"
		NODERV=2223
		NODENV=2200
		MAXRV=2299
		;;
	*)
		die "Unknown/unsupported system architecture: ${ARCH}"
		;;
esac


# Pre-flight checks.
[ $(id -u) -eq 0 ] && die "Please do not run this script under 'sudo' or as root.";
[ -d "./server/lib" ] || die "Please run this script from the Reactor install directory.";

instnode=""
force_inst=""
while getopts "P:V:Uh" arg; do
	case ${arg} in
		P)
			instnode="$OPTARG"
			;;
		U)
			force_inst="Y"
			;;
		V)
			if [[ ${OPTARG} =~ ^[0-9]{2}[.][0-9]+[.][0-9]+$ ]]; then
				NODEVER="$OPTARG"
				xv=$( echo $NODEVER | cut -d . -f 2 )
				nv=${NODEVER/.*/}
				NODERV=$(( $nv * 100 + $xv ))
			else
				echo "Invalid version format for -V; expecting <major>.<minor>.<patch>"
				echo "For example: -V ${NODEVER}"
				exit 255
			fi
			;;
		h)
			usage
			;;
		\?)
			usage
			;;
	esac
done

echo "                  Script version: ${MYVER}"
echo "      Recommended nodejs version: v${NODEVER} (${TAG})"
echo "Minimum supported nodejs version: v${NODENV:0:2}.${NODENV:2:2}"
echo "Maximum supported nodejs version: v${MAXRV:0:2}.${MAXRV:2:2}"

# Figure out the node situation.
doinst=1
nodeexec="$( which node )"
if which node >/dev/null; then
	if [ -n "$force_inst" ]; then
		doinst=1
	elif [ -n "$instnode" ]; then
		echo
		echo "You specified a nodejs package on the command line: ${instnode}"
		echo "This version will be installed for the local user (only)."
	else
		nodever=$(node -v)
		nv=${nodever:1}
		xv=$( echo $nv | cut -d . -f 2 )
		nv=${nv/.*/}
		zv=$(( $nv * 100 + $xv ))
		echo "        Installed nodejs version: ${nodever} (at $(which node))"
		#echo "zv=${zv} NODERV=${NODERV} NODENV=${NODENV} MAXRV=${MAXRV}"
		if [ $zv -gt $MAXRV ]; then
			echo
			echo "The version of nodejs currently installed (${nodever}) may not be compatible."
			echo "It is newer than the highest version this script recognizes as supported."
			echo "Please check the Reactor installation documentation for the latest information"
			echo "on supported versions."
			askyn ans "Do you want me to install the recommended version ($NODEVER) for this user only? "
			if [ "$ans" == "N" ]; then
				echo "OK. Please install a known-compatible version of nodejs manually."
				exit 1
			fi
		elif [ $zv -ge $NODERV ]; then
			echo
			echo "The version of nodejs currently installed is ${nodever} (compatible)."
			doinst=0
		elif [ $zv -ge $NODENV ]; then
			echo
			echo "The version of nodejs currently installed ${nodever} is below the recommended"
			echo "version ${NODEVER}, but it is believed to be compatible. Upgrade is optional."
			askyn ans "Do you want me to upgrade to the recommended version ${NODEVER} for this user only? "
			if [ "$ans" == "N" ]; then
				doinst=0
			fi
		else
			echo
			echo "The version of nodejs currently installed ${nodever} is not compatible with Reactor."
			askyn ans "Do you want me to install the recommended version ($NODEVER) for this user only? "
			if [ "$ans" == "N" ]; then
				echo "OK. Please install a known-compatible version of nodejs manually."
				exit 1
			fi
		fi
	fi
elif [ -z "$instnode" ]; then
	echo
	echo "Nodejs does not appear to be installed, or is not in your PATH."
fi

NODEPKG=""
if [ $doinst -ne 0 ]; then
	if [ -z "$instnode" ]; then
		NODEPKG="node-v${NODEVER}-linux-${TAG}.tar.gz"
		echo "I can download a compatible version (v${NODEVER}) and install it locally"
		echo "(for this user account only -- not system-wide)."
		askyn ans "Do you want me to download and install ${NODEPKG} now? "
		if [ "$ans" == "Y" ]; then
			instnode="/tmp/${NODEPKG}"
			p="https://nodejs.org/dist/v${NODEVER}/${NODEPKG}"
			curl -f -L -o "${instnode}" ${p} || die "${p}: failed, please try again or download/install node manually.";
		else
			die "OK. Download a version you like better, and re-run: $0 -N <path-to-nodejs-download>"
		fi
	fi
fi

# Start the installation.
echo ""
umask 022

if [ -n "$instnode" ]; then
	version=$(basename $instnode)
	dir=${version/.tar.*z/}
	suff="${version##*.}"

	echo;echo "Creating local (user) nodejs installation in ${HOME}/.local/lib/nodejs/${dir}..."
	mkdir -p $HOME/.local/lib/nodejs
	echo -n "Unpacking nodejs archive... this takes a moment... "
	if [[ "$suff" == "xz" ]]; then
		tar -xJf ${instnode} -C $HOME/.local/lib/nodejs || die "Can't read archive ${instnode}"
	else
		tar -xzf ${instnode} -C $HOME/.local/lib/nodejs || die "Can't read archive ${instnode}"
	fi

	# Link ~/.local/bin to package executables
	mkdir -p $HOME/.local/bin
	ln -sf $HOME/.local/lib/nodejs/${dir}/bin/* $HOME/.local/bin/

	# Make sure ~/.local/bin is in PATH
	echo;echo -n "Adding local (user) executables to search path (via ${HOME}/.profile)... "
	sed -i '/^export PATH=\${HOME}\/\.local\/bin/d' ${HOME}/.profile
	cat <<EOF >>${HOME}/.profile
export PATH=\${HOME}/.local/bin:\$PATH
EOF
	nodeexec="${HOME}/.local/bin/node"
	PATH="$(dirname ${nodeexec}):${PATH}"
	hash -r
	echo;echo "Done! You may need to log out and log back in to access the new version."
fi

exit 0
