#!/bin/zsh
export EXECUTION_DIR=$(pwd)

SCWRYPTS_ROOT="${0:a:h}"
source "$SCWRYPTS_ROOT/zsh/common.zsh" || exit 42
#####################################################################

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

		OPTIONS
		  -e, --env <env-name>   set environment; overwrites SCWRYPTS_ENV
		  -n, --no-log           skip logging (useful when calling scwrypts as an api)
		  -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 ERROR=0

	while [[ $# -gt 0 ]]
	do
		case $1 in
			-h | --help )
				__USAGE
				return 0
				;;
			-n | --no-log )
				[ ! $SUBSCWRYPT ] && SUBSCWRYPT=0
				shift 1
				;;
			-e | --env )
				[ $ENV_NAME ] && __WARNING 'overwriting session environment'
				ENV_NAME="$2"
				__STATUS "using CLI environment '$ENV_NAME'"
				shift 2
				;;
			-l | --list )
				__OUTPUT_COMMAND_LIST
				return 0
				;;
			-- )
				shift 1
				break # pass arguments after '--' to the scwrypt
				;;
			-* )
				__ERROR "unrecognized argument '$1'"
				shift 1
				;;
			* )
				SEARCH_PATTERNS+=$1
				shift 1
				;;
		esac
	done

	__ERROR_CHECK

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

	local SCRIPT=$(__SELECT_SCRIPT $SEARCH_PATTERNS)
	[ ! $SCRIPT ] && exit 2
	export SCWRYPT_NAME=$SCRIPT

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

	[[ $ENV_REQUIRED -eq 1 ]] && {
		[ ! $ENV_NAME ] && ENV_NAME=$(__SELECT_ENV)
		local ENV_FILE=$(__GET_ENV_FILE $ENV_NAME)

		[ -f "$ENV_FILE" ] && source "$ENV_FILE" \
			|| __FAIL 5 "missing or invalid environment '$ENV_NAME'"

		export ENV_NAME
	}

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

	local RUN_STRING=$(__GET_RUN_STRING $SCRIPT $ENV_NAME)
	[ ! $RUN_STRING ] && exit 3

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

	local LOGFILE=$(__GET_LOGFILE $SCRIPT)

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

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

	{
		[ $HEADER ] && echo $HEADER
		echo '\033[1;33m--- BEGIN OUTPUT -------------------------\033[0m'
		eval $RUN_STRING $@
		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
	)
}

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

__OUTPUT_COMMAND_LIST() {
	local LAST_TYPE LAST_SUBSET
	for SCRIPT in $(__GET_AVAILABLE_SCRIPTS)
	do
		TYPE=$(echo $SCRIPT | sed 's/\/.*//')
		SUBSET=$(echo $SCRIPT | sed 's/.*\/\(.*\)\/[^\/]*$/\1/')
		[[ ! $LAST_TYPE =~ $TYPE ]] && {
			echo >&2
			echo "\\033[1;32m$TYPE scwrypts\\033[0m" >&2
			LAST_SUBSET=''
		}
		[ $LAST_SUBSET ] && [[ ! $LAST_SUBSET =~ $SUBSET ]] && {
			echo >&2
		}
		printf '  - ' >&2
		echo $SCRIPT
		LAST_TYPE=$TYPE
		LAST_SUBSET=$SUBSET
	done
}

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

__SELECT_SCRIPT() {
	local SCRIPT
	local SCRIPTS=$(__GET_AVAILABLE_SCRIPTS)
	local SEARCH=($@)

	[[ ${#SEARCH[@]} -eq 0 ]] && {
		SCRIPT=$(echo $SCRIPTS | __FZF 'select a script')
	}

	[[ ${#SEARCH[@]} -eq 1 ]] && [ -f ./$SEARCH ] && {
		SCRIPT=$SEARCH
	}

	[ ! $SCRIPT ] && [[ ${#SEARCH[@]} -gt 0 ]] && {
		SCRIPT=$SCRIPTS
		for PATTERN in $SEARCH
		do
			SCRIPT=$(echo $SCRIPT | grep $PATTERN)
		done

		[ ! $SCRIPT ] && __FAIL 2 "no script found by name '$@'"

		[[ $(echo $SCRIPT | wc -l) -gt 1 ]] && {
			__STATUS "more than one script matched '$@'"
			SCRIPT=$(echo $SCRIPT | __FZF 'select a script')
		}
	}

	echo $SCRIPT
}

__GET_RUN_STRING() {
	local SCRIPT="$1"
	local ENV_NAME="$2"
	local TYPE=$(echo $SCRIPT | sed 's/\/.*$//')

	local RUN_STRING

	local _VIRTUALENV="$SCWRYPTS_VIRTUALENV_PATH/$TYPE/bin/activate"
	[ -f $_VIRTUALENV ] && source $_VIRTUALENV

	case $TYPE in
		py ) __CHECK_DEPENDENCY python || return 1
			RUN_STRING="python -m $(echo $SCRIPT | sed 's/\//./g; s/\.py$//; s/\.\.//')"

			CURRENT_PYTHON_VERSION=$(python --version | sed 's/^[^0-9]*\(3\.[^.]*\).*$/\1/')

			echo $__PREFERRED_PYTHON_VERSIONS | grep -q $CURRENT_PYTHON_VERSION || {
				__WARNING "only tested on the following python versions: $(printf ', %s.x' ${__PREFERRED_PYTHON_VERSIONS[@]} | sed 's/^, //')"
				__WARNING 'compatibility may vary'
			}
			;;

		zsh ) __CHECK_DEPENDENCY zsh || return 1
			RUN_STRING="noglob ./$SCRIPT"
			;;

		zx ) __CHECK_DEPENDENCY zx || return 1
			RUN_STRING="FORCE_COLOR=3 ./$SCRIPT.mjs"
			;;

		* ) __ERROR "unsupported script type '$SCRIPT_TYPE'"
			return 2
			;;
	esac

	RUN_STRING="SCWRYPTS_ENV='$ENV_NAME' $RUN_STRING"
	[ -f $_VIRTUALENV ] && RUN_STRING="source '$_VIRTUALENV'; $RUN_STRING"

	echo $RUN_STRING
}

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

	echo $SCRIPT | grep -q 'zsh/scwrypts/logs' && 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() {
	local SCRIPT="$1"

	[ $SUBSCWRYPT ] \
		|| [[ $SCRIPT =~ scwrypts/logs ]] \
		|| [[ $SCRIPT =~ interactive ]] \
		&& return 0

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

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