#!/bin/bash

known_list="request valid-url jsdom node-fetch digest-fetch"

#  backup MM modules  config

base=$HOME/MagicMirror
saveDir=$HOME/MM_backup
logpath=$HOME/MagicMirror/installers
logfile=$HOME/MagicMirror/installers/restore.log
user_name=''
# is this a mac
mac=$(uname -s)
fetch=
process_args(){
local OPTIND

while getopts ":hs:b:r:u:f" opt
do
    #echo opt=$opt
    case $opt in
    	# help
	    h) 		echo
				echo $0 takes optional parameters
				echo
				echo -e "\t -s MagicMirror_dir"
				echo -e	"\t\tdefault $base"
				echo
				echo -e "\t -b backup_dir "
				echo -e	"\t\tdefault $saveDir"
				echo
				echo -e "\t -f "
				echo -e	"\t\tfetch/clone repo and restore latest tag"
				echo
				echo -e "\t -r github repository name (reponame)"
				echo -e	"\t\ttypically https://github.com/username/reponame.git"
				echo -e	"\t\tdefault output of git remote -v (if set)"
				echo -e "\t\t -r overrides the git remote setting"
				echo
				echo -e "\t -u github username"
				echo -e	"\t\tdefault none"

				exit 1
		 ;;
    s)
		# source MagicMirror folder
      b=$(echo $OPTARG | tr -d [:blank:])
			if [ -d $HOME/$b ]; then
				base=$HOME/$b
			else
				if [ -d $b ]; then
					base=$b
				else
					echo unable to find Source folder $OPTARG | tee -a $logfile
					exit 2
				fi
			fi
			echo MagicMirror folder to update is $base | tee -a $logfile
    ;;
    b)
			echo processing backup parm
		# backup folder
			saveDir=$(echo $OPTARG | tr -d [:blank:])
			# if the backup/restrore folder exists in users home
			if [ -d $HOME/$saveDir ]; then
				  # use it
					saveDir=$HOME/$saveDir
			else
				# if the folder doesn't exist
			  if [ ! -d $saveDir ]; then
			  	# check to see if it starts with a /
			  	if [ ${saveDir:0:1} != "/" ]; then
			  		# if its a full path to the home folder
			  		# it will be created on clone
			  		if [ $HOME/$saveDir != $saveDir ]; then
							echo backup folder $saveDir not found, will be created on git clone | tee -a $logfile
						fi
					fi
				fi
			fi
			echo backup folder is $saveDir | tee -a $logfile
    ;;
	u)
			# username
			user_name=$(echo $OPTARG | tr -d [:blank:])
		;;
	r)
			# github repo name or url
			repo=$OPTARG
			# check for full url specified, we only want the name
			IFS='/'; repoIN=($OPTARG); unset IFS;
			# if there were slashes
			if [ ${#repoIN[@]} -gt 1 ]; then
				# get the last element of split array
				index=${#repoIN[@]}
				# get the  name
				repot=${repoIN[$((index -1))]}
				# user is one array element earlier
				# get the user name from the URL
				user_name=${repoIN[$(($index-2))]}
				# check for '.git'
				IFS='.'; repoN=($repot); unset IFS;
				# get just the name
				repo_name=${repoN[0]}
				fetch=true
			else
				repo_name=$(echo $repo | tr -d [[:blank:]])
				fetch=true
			fi
		;;
	f)
			fetch=true
			fetch_tag=
			vparm=${@:$OPTIND}
			if [[ ${vparm:0:1} != "-" ]];then
          		   fetch_tag=$(echo ${@:$OPTIND}| cut -d' ' -f1)
          		   OPTIND=$((OPTIND+1))
      			fi
		;;
	*) echo "Illegal option '-$OPTARG'" && exit 3
	 ;;
    esac
done
}

# if this script was started directly then arg0 is 'mm_backup.sh', else it is the first argument provided (oops) 

if [[ "$0" == *.sh ]]; then
  process_args "$@"
else
  if [ $# -ge 1 ]; then 
  	process_args "$0 $@"
  else
  	process_args "$0"
  fi
fi

if [ $mac == 'Darwin' ]; then
	cmd=greadlink
else
	cmd=readlink
fi

if [ ! -d $logpath ]; then
	mkdir $logpath
fi
date +"restore starting  - %a %b %e %H:%M:%S %Z %Y" >>$logfile
echo restoring MM configuration from $saveDir to $base | tee -a $logfile
echo
if [ ! -e $base/node_modules/@electron/rebuild ];  then 
    cd $base
    if [ -e $base/node_modules/.bin/electron-rebuild ]; then 
	# remove the old version	  
      npm uninstall electron-rebuild >>$logfile 2>&1
	fi	  
	# install the new version 
	npm install @electron/rebuild >>$logfile 2>&1
fi

cd $HOME

# fetch  use latest tag (bu highest number)

if [ "$fetch." != "." ]; then
	echo trying to fetch $repo_name from github | tee -a $logfile
	# if the directory doesn't exist
	if [ ! -d $saveDir ]; then
						# and we have username and repo name
			if [ "$user_name." != "." -a "$repo_name." != "." ]; then
				echo folder $saveDir does not exist, will clone it from github | tee -a $logfile
				touch $saveDir &>/dev/null
				if [ $? -ne 0 ]; then
					echo unable to create backup folder $saveDir
					exit
				else
				  rm $saveDir
				fi
				git clone "https://github.com/$user_name/$repo_name" $saveDir >/dev/null 2>&1
				cd $saveDir
			else
				echo -e "\t\t need both the github username and the github repository name to retrieve the github repo" | tee -a $logfile
				exit 4
			fi
  else
  	cd $saveDir
  	if [ "$(git remote -v)." != "." ]; then
  		repo_name=$(git remote -v | head -n1 | awk '{print $2}')
  		echo $saveDir exists fetching all tags from $repo_name | tee -a $logfile
  		if [ "$user_name." != "." -a "$repo_name." != "." ]; then
				git fetch --all --tags
			else
				echo -e "\t\t need both the github username and the github repository name" | tee -a $logfile
				exit 5
			fi
		else
			echo -e "$saveDir exists, but its not a linked git repo, can't fetch or clone" | tee -a $logfile
			exit 6
		fi
	fi
else
	if [ ! -d $saveDir ]; then
		echo Backup directory $saveDir not found, exiting | tee -a $logfile
		exit 1
	fi
	cd $saveDir
fi
# get the last numeric tag
if [ "$fetch_tag." != "." ]; then
	last_tag=$fetch_tag
else
	last_tag=$(git tag -l  | sort -g -r | head -n1)
fi
# get on some known branch
git checkout main >/dev/null 2>&1
# delete the temp branch for the restore
git branch -D restore-branch >/dev/null 2>&1
# create the branch from the tag
git checkout tags/$last_tag -b restore-branch >/dev/null 2>&1

echo created git branch from last tag = $last_tag | tee -a $logfile
# restore the config for MM
cp -p $saveDir/config.js $base/config
# restore the custom/.css for MM (no error if not found)
cp -p $saveDir/custom.css $base/css 2>/dev/null

echo restored config.js and custom.css | tee -a $logfile

repo_list=$saveDir/module_list

echo processing module_list >>$logfile
if [ -e $repo_list ]; then
	if [ $mac != 'Darwin' ]; then
		SAVEIFS=$IFS   # Save current IFS
		IFS=$'\n'
	fi
	# split output on new lines, not spaces
	urls=($(cat $repo_list))
	if [ $mac != 'Darwin' ]; then
			IFS=$SAVEIFS
	fi

	# if there modules to restore
	if [ ${#urls} -gt 0 ]; then

		# restore the repos

		cd $base/modules

			# loop thru the modules listed
			for repo_url in "${urls[@]}"
			do
				if [[ $repo_url =~ "bugsounet" ]]; then
					echo -----WARNING source repo, $repo_url removed, skipping | tee -a $logfile
					echo
					continue
				fi
				module=$(echo $repo_url | awk -F/ '{print $(NF)}' | awk -F. '{print $1}')
				# if the module folder does not exist
				if [ ! -d $module ]; then
					echo restoring $module | tee -a $logfile
					gc=$(git clone $repo_url 2>&1)
					gc_rc=$?
					if [ $gc_rc -eq 0 ]; then
						cd $module
						if [ -e package.json ]; then
							if [ $(grep -e \""dependencies\"" -e \""postinstall\"" package.json | wc -l) -gt 0  ]; then
								echo module $module contains package.json, doing npm install | tee -a $logfile
								npm install --only=prod --no-audit --no-fund --loglevel error --legacy-peer-deps 2>>$logfile >> $logfile
							fi
						else
							echo module $module DOES NOT contain package.json | tee -a $logfile
						fi
						# if there is a folder of module specific files saved by backup
						if [ -d $saveDir/$module ]; then
							# copy them from the backup
							echo there were files saved for this module , restoring | tee -a $logfile
							cp -a $saveDir/$module/. $base/modules/$module
						fi
						cd - >/dev/null
					fi
				else
					echo -e "\e[91m $module folder already exists, skipping restore from $repo_url \e[90m" | tee -a $logfile
					tput init 2>/dev/null
					echo
				fi
				echo
			done

			# lets check for modules with missing requires (libs removed from MM base)
			# this skips any default modules
			echo Checking for modules with removed libraries| tee -a $logfile
			mods=($(find . -maxdepth 2 -type f -name  node_helper.js | awk -F/ '{print $2}'))

			# loop thru all the installed modules
			for  mod in "${mods[@]}"
			do
				# get the require statements from the node helper
				requires=($(grep -e "require(" $mod/node_helper.js | awk -F '[()]' '{print $2}' | tr -d '"' | tr -d "'"))
				# loop thru the requires
				for require in "${requires[@]}"
				do
					# check it against the list of known lib removals
					case " $known_list " in (*" $require "*) :;; (*) false;; esac
					# if found in the list
					if [ $? == 0 ]; then
						# if no package.json, we would have to create one
						cd $mod
						if [ ! -e package.json ]; then
							echo -e ' \n\t ' package.json not found for module $mod
							echo -e ' \n\t\t ' adding package.json for module $mod | tee -a $logfile
							npm init -y >/dev/null 2>&1
						fi
						# if package.json exists, could have been just added
						if [ -e package.json ]; then
							# check for this library in the package.json
							pk=$(grep $require package.json)
							# if not present, need to do install
							if [ "$pk." == "." ]; then
								echo -e ' \n\t\t ' require for $require in module $mod not found in package.json | tee -a $logfile
								echo -e ' \n\t\t ' installing $require for module $mod | tee -a $logfile
								npm install $require --save --no-audit --no-fund --loglevel error --legacy-peer-deps --only=prod 2>&1 >> $logfile
							fi
						fi
						cd - >/dev/null
					fi
				done
			done
	fi
	echo
	echo restore completed, you can start MagicMirror now | tee -a $logfile
else
	echo no saved module repo list | tee -a $logfile
fi
date +"restore ended  - %a %b %e %H:%M:%S %Z %Y" >>$logfile