# What the commands share: bash-tools, the engine and the rc file. Sourced by the commands, not run.
#
# The rules and the work are the engine's (opensim-api): this tool shows the questions, gives the answers to the engine and shows what
# it says. bash-tools and the engine are dependencies (composer, or the packages that link them in vendor/magicoli), found in vendor/
# of this project; OPENSIM_API names another engine, which is how the tests use a stand-in.

_here=$(dirname "$(realpath "${BASH_SOURCE[0]}" 2>/dev/null || echo "${BASH_SOURCE[0]}")")
CLI_ROOT=$(cd "$_here/../.." && pwd)
unset _here

_helpers="$CLI_ROOT/vendor/magicoli/bash-tools/bin/bash-helpers"
[[ -f "$_helpers" ]] || {
	echo "${0##*/}: bash-tools is not installed (composer install in $CLI_ROOT)" >&2
	exit 1
}
# shellcheck disable=SC1090
source "$_helpers"
unset _helpers

OPENSIM_API=${OPENSIM_API:-$CLI_ROOT/vendor/magicoli/opensim-engine/bin/opensim-api}
[[ -x "$OPENSIM_API" ]] || die "The engine is not installed (composer install in $CLI_ROOT)"
require jq

# The rc file, for any script of the ecosystem: it may fix the PATH (which php)
if [[ -r "$(dirname "$OPENSIM_API")/../lib/rc-helpers" ]]; then
	# shellcheck disable=SC1091
	source "$(dirname "$OPENSIM_API")/../lib/rc-helpers" && read_rc
fi

# Ask the engine: engine POST /setups/quick --data=- < body
engine() {
	"$OPENSIM_API" "$@"
}

# Act on this machine through the engine (src/php/run.php): run COMMAND [ARGUMENTS]; its status is the one of the command
run() {
	php "$CLI_ROOT/src/php/run.php" "$@"
}

say() { printf '%s\n' "$*"; }
debug_log() {
	[ -n "${DEBUG}" ] || return 0
	[ "$DEBUG" = "yes" ] || return 0
	say "$PGM: [DEBUG] $*" >&2
}
error() {
	say "$PGM: [ERROR] $*" >&2
}
die() {
	error "$*"
	exit 1
}

# A question for the person at the terminal, even when this script comes from a pipe; yes when nobody can answer
ask() {
	[[ -n "$ASSUME_YES" ]] && return 0
	[[ -r /dev/tty ]] || return 0
	local answer
	read -r -p "$1 [Y/n] " answer </dev/tty
	[[ ! $answer =~ ^[Nn] ]]
}

as_root() {
	if [[ $(id -u) -eq 0 ]]; then
		"$@"
	elif command -v sudo >/dev/null 2>&1; then
		sudo --preserve-env=${PRESERVE_ENV:-} "$@"
	else
		die "this needs administrator rights: run it as root, or install sudo"
	fi
}

as_system_user() {
	system_user=${system_user:-}
	if [[ -z "$system_user" || "$(id -un)" == "$system_user" ]]; then
		"$@"
	# elif [[ $(id -u) -eq 0 ]]; then
	# 	runuser -u "$system_user" -- "$@"
	elif command -v sudo >/dev/null 2>&1; then
		sudo -u ${system_user} --preserve-env=${PRESERVE_ENV:-} "$@"
	else
		die "this needs administrator rights: run it as root, or install sudo"
	fi
}

# Read private setup inputs as their caller and pass them to the service account without changing their permissions.
run_setup() {
	local -a arguments=("$@") inputs=() indexes=()
	local index position input_file input_dir= destination status=0 option
	if [[ -z "${system_user:-}" || "$(id -un)" == "$system_user" ]]; then
		"$CLI_ROOT/libexec/setup" "$@"
		return $?
	fi
	for ((index = 0; index < ${#arguments[@]}; index++)); do
		input_file=
		case "${arguments[index]}" in
			--apply)
				((index + 1 < ${#arguments[@]})) || die "--apply requires a JSON file"
				input_file=${arguments[index+1]}; arguments[index+1]=- ;;
			--apply=*) input_file=${arguments[index]#*=}; arguments[index]=--apply=- ;;
		esac
		if [[ -n "$input_file" && "$input_file" != - ]]; then
			[[ -r "$input_file" ]] || die "cannot read prepared setup: $input_file"
			as_system_user "$CLI_ROOT/libexec/setup" "${arguments[@]}" <"$input_file"
			return $?
		fi
	done
	for ((index = 0; index < ${#arguments[@]}; index++)); do
		case "${arguments[index]}" in
			--config | --region-config)
				option=${arguments[index]}
				((index + 1 < ${#arguments[@]})) || die "$option requires a file"
				input_file=${arguments[index+1]} ;;
			--config=* | --region-config=*) input_file=${arguments[index]#*=} ;;
			*) continue ;;
		esac
		[[ -r "$input_file" ]] || die "cannot read setup input: $input_file"
		inputs+=("$input_file"); indexes+=("$index")
		[[ "${arguments[index]}" == *=* ]] || ((index += 1))
	done
	if ((${#inputs[@]})); then
		input_dir=$(as_system_user mktemp -d /tmp/opensim-setup.XXXXXXXX) || die "could not create private setup inputs"
	fi
	for ((position = 0; position < ${#inputs[@]}; position++)); do
		index=${indexes[position]}
		destination=$input_dir/input-$position
		if ! as_system_user sh -c 'umask 077; cat > "$1"' setup "$destination" <"${inputs[position]}"; then
			as_system_user rm -rf -- "$input_dir" || true
			die "could not transfer setup input: ${inputs[position]}"
		fi
		case "${arguments[index]}" in
			*=*) option=${arguments[index]%%=*}; arguments[index]=$option=$destination ;;
			*) arguments[index+1]=$destination ;;
		esac
	done
	as_system_user "$CLI_ROOT/libexec/setup" "${arguments[@]}" || status=$?
	[[ -z "$input_dir" ]] || as_system_user rm -rf -- "$input_dir" || true
	return "$status"
}
