#!/bin/zsh
export EXECUTION_DIR=$(pwd)
source "${0:a:h}/zsh/lib/import.driver.zsh" || exit 42

#####################################################################

__RUN() {
	local USAGE='
		usage: scwrypts [OPTIONS ...] SCRIPT -- [SCRIPT OPTIONS ...]

		OPTIONS
		  -g, --group <group-name>    only use scripts from the indicated group
		  -t, --type <type-name>      only use scripts of the indicated type
		  -m, --name <scwrypt-name>   only run the script if there is an exact match 
		                                (requires type and group)

		  -e, --env <env-name>   set environment; overwrites SCWRYPTS_ENV
		  -n, --no-log           skip logging and run in quiet mode

		  --update   update scwrypts library to latest version

		  -v, --version   print out scwrypts version and exit
		  -l, --list      print out command list and exit
		  -h, --help      display this message and exit
	'
	cd "$SCWRYPTS_ROOT"

	local ENV_NAME="$SCWRYPTS_ENV"
	local SEARCH_PATTERNS=()

	local VARSPLIT SEARCH_GROUP SEARCH_TYPE SEARCH_NAME

	local ERROR=0

	while [[ $# -gt 0 ]]
	do
		case $1 in
			-t | --type )
				[ ! $2 ] && ERROR "missing value for argument $1" && break
				SEARCH_TYPE=$2
				shift 2
				;;
			-g | --group )
				[ ! $2 ] && ERROR "missing value for argument $1" && break
				SEARCH_GROUP=$2
				shift 2
				;;
			-m | --name )
				[ ! $2 ] && ERROR "missing value for argument $1" && break
				SEARCH_NAME=$2
				shift 2
				;;

			-[a-z][a-z]* )
				VARSPLIT=$(echo "$1 " | sed 's/^\(-.\)\(.*\) /\1 -\2/')
				set -- $(echo " $VARSPLIT ") ${@:2}
				;;
			-h | --help )
				USAGE
				return 0
				;;
			-n | --no-log )
				[ ! $SUBSCWRYPT ] && SUBSCWRYPT=0
				shift 1
				;;
			-e | --env )
				[ ! $2 ] && ERROR "missing value for argument $1" && break
				[ ! $SUBSCWRYPTS ] \
					&& [ $ENV_NAME ] \
					&& WARNING 'overwriting session environment' \
					;

				ENV_NAME="$2"
				STATUS "using CLI environment '$ENV_NAME'"
				shift 2
				;;
			-l | --list )
				SCWRYPTS__GET_AVAILABLE_SCWRYPTS
				return 0
				;;
			-v | --version )
				echo scwrypts $(cd "$SCWRYPTS__ROOT__scwrypts"; git describe --tags)
				return 0
				;;
			--update )
				cd "$SCWRYPTS__ROOT__scwrypts"
				git fetch --quiet origin main
				local SYNC_STATUS=$?

				git diff --exit-code origin/main -- . >&2
				local DIFF_STATUS=$?

				[[ $SYNC_STATUS -eq 0 ]] && [[ $DIFF_STATUS -eq 0 ]] && {
					SUCCESS 'already up-to-date with origin/main'
				} || {
					git rebase --autostash origin/main \
						&& SUCCESS 'up-to-date with origin/main' \
						|| {
							git rebase --abort
							ERROR 'unable to update scwrypts; please try manual upgrade'
							REMINDER "installation in '$(pwd)'"
						}
				}
				return 0
				;;
			-- )
				shift 1
				break # pass arguments after '--' to the scwrypt
				;;
			--* )
				ERROR "unrecognized argument '$1'"
				shift 1
				;;
			* )
				SEARCH_PATTERNS+=($1)
				shift 1
				;;
		esac
	done

	[ $SEARCH_NAME ] && {
		[ ! $SEARCH_TYPE  ] && ERROR '--name requires --type argument'
		[ ! $SEARCH_GROUP ] && ERROR '--name requires --group argument'
	}

	CHECK_ERRORS

	##########################################

	local SCWRYPTS_AVAILABLE
	local POTENTIAL_ERROR="no such scwrypt exists:"
	
	SCWRYPTS_AVAILABLE=$(SCWRYPTS__GET_AVAILABLE_SCWRYPTS)

	[ $SEARCH_NAME ] && {
		POTENTIAL_ERROR+="\n   NAME     : '$SEARCH_NAME'"
		POTENTIAL_ERROR+="\n   TYPE     : '$SEARCH_TYPE'"
		POTENTIAL_ERROR+="\n   GROUP    : '$SEARCH_GROUP'"
		SCWRYPTS_AVAILABLE=$({
			echo $SCWRYPTS_AVAILABLE | head -n1
			echo $SCWRYPTS_AVAILABLE | sed -e 's/\x1b\[[0-9;]*m//g' | grep "^$SEARCH_NAME *$SEARCH_TYPE *$SEARCH_GROUP\$"
		})
	}

	[ ! $SEARCH_NAME ] && {
		[ $SEARCH_TYPE ] && {
			POTENTIAL_ERROR+="\n   TYPE     : '$SEARCH_TYPE'"
			SCWRYPTS_AVAILABLE=$(\
				{
					echo $SCWRYPTS_AVAILABLE | head -n1
					echo $SCWRYPTS_AVAILABLE | grep ' [^/]*'$SEARCH_TYPE'[^/]* '
				} \
				| awk '{$2=""; print $0;}' \
				| sed 's/ \+$/'$(printf $__COLOR_RESET)'/; s/ \+/^/g'  \
				| column -ts '^'
			)
		}

		[ $SEARCH_GROUP ] && {
			POTENTIAL_ERROR+="\n   GROUP    : '$SEARCH_GROUP'"
			SCWRYPTS_AVAILABLE=$(
				{
					echo $SCWRYPTS_AVAILABLE | head -n1
					echo $SCWRYPTS_AVAILABLE | grep "$SEARCH_GROUP"'[^/]*$'
				} \
				| awk '{$NF=""; print $0;}' \
				| sed 's/ \+$/'$(printf $__COLOR_RESET)'/; s/ \+/^/g'  \
				| column -ts '^'
			)
		}

		[[ ${#SEARCH_PATTERNS[@]} -gt 0 ]] && {
			POTENTIAL_ERROR+="\n   PATTERNS : $SEARCH_PATTERNS"
			local P
			for P in ${SEARCH_PATTERNS[@]}
			do
				SCWRYPTS_AVAILABLE=$(
					{
						echo $SCWRYPTS_AVAILABLE | head -n1
						echo $SCWRYPTS_AVAILABLE | grep $P
					}
				)
			done
		}
	}

	[[ $(echo $SCWRYPTS_AVAILABLE | wc -l) -lt 2 ]] && ERROR "$POTENTIAL_ERROR"

	CHECK_ERRORS

	##########################################

	local NAME="$SEARCH_NAME"
	local TYPE="$SEARCH_TYPE"
	local GROUP="$SEARCH_GROUP"

	[[ $(echo $SCWRYPTS_AVAILABLE | wc -l) -eq 2 ]] \
		&& SCWRYPT_SELECTION=$(echo $SCWRYPTS_AVAILABLE | tail -n1) \
		|| SCWRYPT_SELECTION=$(echo $SCWRYPTS_AVAILABLE | FZF "select a script to run" --header-lines 1)
	[ $SCWRYPT_SELECTION ] || exit 2

	SCWRYPTS__SEPARATE_SCWRYPT_SELECTION $SCWRYPT_SELECTION

	export SCWRYPT_NAME=$NAME
	export SCWRYPT_TYPE=$TYPE
	export SCWRYPT_GROUP=$GROUP

	##########################################

	local ENV_REQUIRED=$(__CHECK_ENV_REQUIRED && echo 1 || echo 0)

	[[ $ENV_REQUIRED -eq 1 ]] && {
		[ ! $ENV_NAME ] && ENV_NAME=$(SCWRYPTS__SELECT_ENV)
		for GROUP in ${SCWRYPTS_GROUPS[@]}
		do
			local ENV_FILE=$(SCWRYPTS__GET_ENV_FILE "$ENV_NAME" "$GROUP")
			source "$ENV_FILE" || FAIL 5 "missing or invalid environment '$GROUP/$ENV_NAME'"

			for f in $(eval 'echo $SCWRYPTS_STATIC_CONFIG__'$GROUP)
			do
				source "$f" || FAIL 5 "invalid static config '$f'"
			done
		done

		export ENV_NAME
	}


	##########################################

	[ ! $SUBSCWRYPT ] \
		&& [[ $ENV_NAME =~ prod ]] \
		&& { __VALIDATE_UPSTREAM_TIMELINE || ABORT; }

	##########################################

	local RUN_STRING=$(SCWRYPTS__GET_RUNSTRING $SCWRYPT_NAME $SCWRYPT_TYPE $SCWRYPT_GROUP)
	[ ! $RUN_STRING ] && exit 3

	##########################################

	local LOGFILE=$(__GET_LOGFILE)

	local HEADER=$(
		[ $SUBSCWRYPT ] && return 0
		echo '====================================================================='
		echo "script : $SCWRYPT_GROUP $SCWRYPT_TYPE $SCWRYPT_NAME"
		echo "run at : $(date)"
		echo "config : $ENV_NAME"
		[ ! $LOGFILE ] && echo '\033[1;33m------------------------------------------\033[0m'
	)

	[ ! $LOGFILE ] && {
		[ $HEADER ] && echo $HEADER
		[ $SUBSCWRYPT ] && {
			eval "$RUN_STRING $(printf "%q " "$@")"
			exit $?
		} || {
			eval "$RUN_STRING $(printf "%q " "$@")" </dev/tty >/dev/tty 2>&1
			exit $?
		}
	}

	{
		[ $HEADER ] && echo $HEADER
		echo '\033[1;33m--- BEGIN OUTPUT -------------------------\033[0m'
		eval "$RUN_STRING $(printf "%q " "$@")"
		EXIT_CODE=$?
		echo '\033[1;33m--- END OUTPUT ---------------------------\033[0m'

		[[ $EXIT_CODE -eq 0 ]] && EXIT_COLOR='32m' || EXIT_COLOR='31m'

		echo "terminated with\\033[1;$EXIT_COLOR code $EXIT_CODE\\033[0m"
	} 2>&1 | tee --append "$LOGFILE"

	exit $(\
		sed -n 's/^terminated with.*code \([0-9]*\).*$/\1/p' $LOGFILE \
			| tail -n1
	)
}

#####################################################################

__CHECK_ENV_REQUIRED() {
	[ $CI ] && return 1

	echo $SCWRYPT_NAME | grep -q 'scwrypts/logs/' && return 1
	echo $SCWRYPT_NAME | grep -q 'scwrypts/environment/' && return 1

	return 0
}

__VALIDATE_UPSTREAM_TIMELINE() {
	STATUS "on '$ENV_NAME'; checking diff against origin/main"

	git fetch --quiet origin main
	local SYNC_STATUS=$?

	git diff --exit-code origin/main -- . >&2
	local DIFF_STATUS=$?

	[[ $SYNC_STATUS -eq 0 ]] && [[ $DIFF_STATUS -eq 0 ]] && {
		SUCCESS 'up-to-date with origin/main'
	} || {
		WARNING
		[[ $SYNC_STATUS -ne 0 ]] && WARNING 'unable to synchronize with origin/main'
		[[ $DIFF_STATUS -ne 0 ]] && WARNING 'your branch differs from origin/main (diff listed above)'
		WARNING

		yN 'continue?' || return 1
	}
}

__GET_LOGFILE() {
	[ $SUBSCWRYPT ] \
		|| [[ $SCWRYPT_NAME =~ scwrypts/logs ]] \
		|| [[ $SCWRYPT_NAME =~ interactive ]] \
		&& return 0

	echo "$SCWRYPTS_LOG_PATH/$(echo $GROUP/$TYPE/$NAME | sed 's/^\.\///; s/\//\%/g').log"
}

#####################################################################
__RUN $@