#!/usr/bin/env bash
# Info: Script to instal NUSHELL for Provisioning
# Author: JesusPerezLorenzo
# Release: 1.0.5
# Date: 8-03-2024

test_runner() {
	echo -e "\nTest installation ... "
	RUNNER_PATH=$(type -P $RUNNER)
	[ -z "$RUNNER_PATH" ] && echo "🛑 Error $RUNNER not found in PATH ! " && exit 1
	if $RUNNER ; then
		echo -e "\n✅ Installation completed successfully ! Use \"$RUNNER\""
	else
		echo -e "\n🛑 Error $RUNNER ! Review installation " && exit 1
	fi
}
register_plugins() {
	local source=$1
	local warn=$2
	[ ! -d "$source" ] && echo "🛑 Error path $source is not a directory" && exit 1
	[ -z "$(ls $source/nu_plugin_* 2> /dev/null)" ] && echo "🛑 Error no 'nu_plugin_*' found in $source to register" && exit 1
	echo -e "Nushell $NU_VERSION plugins registration \n"
	if [ -n "$warn" ] ; then
		echo -e  $"❗Warning: Be sure Nushell plugins are compiled for same Nushell version $NU_VERSION\n  otherwise will probably not work and will break installation !\n"
	fi
	for plugin in ${source}/nu_plugin_*
	do
	    if $source/nu -c "register \"${plugin}\" " 2>/dev/null ; then
		   echo -en "$(basename $plugin)"
		   if [[ "$plugin" == *_notifications ]] ; then
		 		echo -e "  registred "
			else
		 		echo -e "\t\t registred "
			fi
		fi
	done

	# Install nu_plugin_tera if available
	if command -v cargo >/dev/null 2>&1; then
		echo -e "Installing nu_plugin_tera..."
		if cargo install nu_plugin_tera; then
			if $source/nu -c "register ~/.cargo/bin/nu_plugin_tera" 2>/dev/null; then
				echo -e "nu_plugin_tera\t\t registred"
			else
				echo -e "❗ Failed to register nu_plugin_tera"
			fi
		else
			echo -e "❗ Failed to install nu_plugin_tera"
		fi
	else
		echo -e "❗ Cargo not found - nu_plugin_tera not installed"
	fi
}

# Check Nickel configuration language installation
check_nickel_installation() {
	if command -v nickel >/dev/null 2>&1; then
		nickel_version=$(nickel --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
		echo -e "Nickel\t\t\t already installed (version $nickel_version)"
		return 0
	else
		echo -e "⚠️  Nickel not found - Optional but recommended for config rendering"
		echo -e "   Install via: \$PROVISIONING/core/cli/tools-install nickel"
		echo -e "   Recommended method: nix profile install nixpkgs#nickel"
		echo -e "   (Pre-built binaries have Nix library dependencies)"
		echo -e "   https://nickel-lang.org/getting-started"
		return 1
	fi
}

install_mode() {
	local mode=$1
	case "$mode" in
	  ui| desktop)
		if cp $PROVISIONING_MODELS_SRC/plugins_defs.nu $PROVISIONING_MODELS_TARGET/plugins_defs.nu ; then
			echo  "Mode $mode installed"
		fi
	  	;;
	  *)
		NC_PATH=$(type -P nc)
		if [ -z "$NC_PATH" ] ; then
		   echo "'nc' command not found in PATH. Install 'nc' (netcat) command."
		   exit 1
		fi
		if cp $PROVISIONING_MODELS_SRC/no_plugins_defs.nu $PROVISIONING_MODELS_TARGET/plugins_defs.nu ; then
			echo  "Mode 'no plugins' installed"
		fi
	esac
}
install_from_url() {
	local target_path=$1
	local lib_mode
	local url_source
	local download_path
	local download_url
	local tar_file

	[ ! -d "$target_path" ] && echo "🛑 Error path $target_path is not a directory" && exit 1
	lib_mode=$(grep NU_LIB $PROVISIONING/core/versions | cut -f2 -d"=" | sed 's/"//g')
	url_source=$(grep NU_SOURCE $PROVISIONING/core/versions | cut -f2 -d"=" | sed 's/"//g')
	download_path="nu-${NU_VERSION}-${ARCH_ORG}-${OS}"
	case "$OS" in
	  linux) download_path="nu-${NU_VERSION}-${ARCH_ORG}-unknown-${OS}-gnu"
		 ;;
	esac
	download_url="$url_source/${NU_VERSION}/$download_path.tar.gz"
	tar_file=$download_path.tar.gz
	echo -e "Nushell $NU_VERSION downloading ..."
	if ! curl -sSfL $download_url -o $tar_file ; then
	 	echo "🛑 Error download $download_url " && exit 1
		return 1
	fi
	echo -e "Nushell $NU_VERSION extracting ..."
	if ! tar xzf $tar_file ; then
	 	echo "🛑 Error download $download_url " && exit 1
		return 1
	fi
	rm -f $tar_file
	if [ ! -d "$download_path" ] ; then
	 	echo "🛑 Error $download_path not found " && exit 1
		return 1
	fi
	echo -e "Nushell $NU_VERSION installing ..."
	if [ -r "$download_path/nu" ] ; then
	    chmod +x $download_path/nu
		if ! sudo cp $download_path/nu $target_path ; then
	 		echo "🛑 Error installing \"nu\" in $target_path"
			rm -rf $download_path
			return 1
		fi
	fi
	rm -rf $download_path
	echo "✅ Nushell and installed in $target_path"
	[[ ! "$PATH" =~ $target_path ]] && echo "❗ Warning: \"$target_path\" is not in your PATH for $(basename $SHELL) ! Fix your PATH settings "
	echo ""
	# TDOO install plguins via cargo ??
	# TODO a NU version without PLUGINS
	# register_plugins $target_path
}

install_from_local() {
	local source=$1
	local target=$2
	local tmpdir

	[ ! -d "$target" ] && echo "🛑 Error path $target is not a directory" && exit 1
	[ ! -r "$source/nu.gz" ] && echo "🛑 Error command 'nu' not found in $source/nu.gz" && exit 1

	echo -e "Nushell $NU_VERSION self installation guarantees consistency with plugins and settings \n"
    	tmpdir=$(mktemp -d)
	cp $source/*gz $tmpdir
	for file in $tmpdir/*gz ; do gunzip $file ; done
	if ! sudo mv $tmpdir/* $target ; then
	   echo -e "🛑 Errors to install Nushell and plugins in \"${target}\""
	   rm -rf $tmpdir
	   return 1
	fi
	rm -rf $tmpdir
	echo "✅ Nushell and plugins installed in $target"
	[[ ! "$PATH" =~ $target ]] && echo "❗ Warning: \"$target\" is not in your PATH for $(basename $SHELL) ! Fix your PATH settings "
	echo ""
	register_plugins $target
}

message_install() {
	local ask=$1
	local msg
	local answer
    	[ -r "$PROVISIONING/resources/ascii.txt" ] && cat "$PROVISIONING/resources/ascii.txt" && echo ""
    	if [ -z "$NU" ] ; then
		echo -e "🛑 Nushell $NU_VERSION not installed is mandatory for \"${RUNNER}\""
		echo -e "Check PATH or https://www.nushell.sh/book/installation.html with version $NU_VERSION"
	else
		echo -e "Nushell $NU_VERSION update for \"${RUNNER}\""
	fi
	echo ""
	if [ -n "$ask" ] && [ -d "$(dirname $0)/nu/${ARCH}-${OS}" ] ; then
	    echo -en "Install Nushell $(uname -m) $(uname) in \"$INSTALL_PATH\" now (yes/no) ? : "
	    read -r answer
	    if [ "$answer" != "yes" ] && [ "$answer" != "y" ] ; then
	    	return 1
	    fi
	fi
	if [ -d "$(dirname $0)/nu/${ARCH}-${OS}" ] ; then
	    install_from_local  $(dirname $0)/nu/${ARCH}-${OS} $INSTALL_PATH
		install_mode "ui"
	else
	    install_from_url $INSTALL_PATH
		install_mode ""
	fi
	echo ""
	echo -e "Checking optional configuration languages..."
	check_nickel_installation
}

set +o errexit
set +o pipefail

RUNNER="provisioning"
export NU=$(type -P nu)

[ -n "$PROVISIONING_ENV" ] && [ -r "$PROVISIONING_ENV" ] && source "$PROVISIONING_ENV"
[ -r "../env-provisioning" ] && source ../env-provisioning
[ -r "env-provisioning" ] && source ./env-provisioning
#[ -r ".env" ] && source .env set
set +o allexport

if [ -n "$1" ] && [ -d "$1" ] && [ -d "$1/core" ] ; then
	export PROVISIONING=$1
else
	export PROVISIONING=${PROVISIONING:-/usr/local/provisioning}
fi

TASK=${1:-check}
shift
if [ "$TASK" == "mode" ] && [ -n "$1" ] ; then
    INSTALL_MODE=$1
    shift
else
    INSTALL_MODE="ui"
fi

ASK_MESSAGE="ask"
[ -n "$1"  ] && [ "$1" == "no-ask" ] && ASK_MESSAGE="" && shift
[ -n "$1"  ] && [ "$1" == "mode-ui" ] && INSTALL_MODE="ui" && shift
[ -n "$1"  ] && [[ "$1" == mode-* ]] && INSTALL_MODE="" && shift

INSTALL_PATH=${1:-/usr/local/bin}

NU_VERSION=$(grep NU_VERSION $PROVISIONING/core/versions | cut -f2 -d"=" | sed 's/"//g')
#ARCH="$(uname -m | sed -e 's/x86_64/amd64/' -e 's/\(arm\)\(64\)\?.*/\1\2/' -e 's/aarch64$/arm64/')"
ARCH="$(uname -m | sed -e 's/amd64/x86_64/' -e 's/\(arm\)\(64\)\?.*/\1\2/' -e 's/aarch64$/arm64/')"
ARCH_ORG="$(uname -m | tr '[:upper:]' '[:lower:]')"
OS="$(uname | tr '[:upper:]' '[:lower:]')"

PROVISIONING_MODELS_SRC=$PROVISIONING/core/nulib/models
PROVISIONING_MODELS_TARGET=$PROVISIONING/core/nulib/lib_provisioning

USAGE="$(basename $0) [install | reinstall | mode | check] no-ask mode-?? "
case $TASK in
	install)
		message_install $ASK_MESSAGE
		;;
	reinstall | update)
	 	INSTALL_PATH=$(dirname $NU)
		if message_install ; then
			test_runner
		fi
		;;
	mode)
		install_mode $INSTALL_MODE
		;;
	check)
		$PROVISIONING/core/bin/tools-install check nu
		;;
	help|-h)
	   	echo "$USAGE"
		;;
	*) echo "Option $TASK not defined"
esac
