#!/usr/bin/env bash

COURSE=cdis/cs/courses/cs400/202401/
API=api/v4/
GITLAB=https://git.doit.wisc.edu/

main() {
    if [[ $# -lt 1 && $# -gt 2 ]]; then
	echo "Usage: cs400 [-v] <command>"
	echo ""
	echo "Available commands include:"
	echo "    init     configures user account to use other cs400 commands"
	echo "    get      retrieves starter folder for a specific assignment"
	echo "    submit   submits assignment from current working directory"
	echo "    check    retrieves feedback for current assignment folder"
	echo "    restart  resets contents of current assignment folder"
	echo ""
	echo "The option -v provides a more verbose display of any errors."
	echo ""
	exit
    fi

    # redirect extra diagnostics and error messages to VERBOSE
    VERBOSE="/dev/null"
    if [[ $(echo "$@" | grep -ic "\-v") > 0 ]]; then
	VERBOSE="/dev/stdout"
    fi

    # switch through command options
    read -p "Enter your NetID username: " NETID
    if [[ ${1,,} = init ]]; then
	init
    else
	readToken # sets TOKEN
	readActivityList # sets ACTIVITYLIST
	if [[ ${1,,} = get ]]; then
	    get
	else
	    confirmActivityWorkingDirectory
	    if [[ ${1,,} = submit ]]; then
		submit
	    elif [[ ${1,,} = check ]]; then
		check
	    elif [[ ${1,,} = restart ]]; then
		restart
	    fi
	fi
    fi
}

init() {
    installJq
    
    # overwrite $USER when run with sudo, to be actual user rather than root
    if [[ $EUID -eq 0 ]]; then export USER="$SUDO_USER"; fi
    
    setupGitlabAccessToken
    readToken # sets TOKEN
    configLocalGitAccount
    addSelfToStudentGroup
}

installJq() {
    echo "Attempting to install jq, when needed."
    if [[ ! $(command -v jq) ]]; then
	if [[ $EUID -ne 0 ]]; then
	    echo "This script requires super user privelege to install jq."
	    echo "Please try running \"sudo cs400 init\"."
	    exit
	fi
	sudo apt update -y
	sudo apt install -y jq
    fi
}

setupGitlabAccessToken() {
    echo ""
    echo "Setup GitLab Access Token:"
    echo ""
    echo "* Note that your personal access token should be kept private like a password.  If you ever lose or worry that someone may have gained access to this private information: You can delete this token through gitlab, and then rerun this script \"cs400 init\" to retrieve and store a new one."
    echo ""
    echo "1) Navigate your browser to https://git.doit.wisc.edu/-/profile/personal_access_tokens"
    echo "2) When prompted to sign in, use the \"UW-Madison NetID\" button at the bottom of this page"
    echo "3) Click the \"Add new token\" button."
    echo "4) Enter \"google cloud vm\" as the token name"
    echo "5) Enter the last day of the semester as the expiration date"
    echo "6) Click to mark every checkboxes under \"Select scopes\""
    echo "7) Click the \"Create personal access token\" button"
    echo "8) Click the \"Copy personal access token button\" button with a clipboard icon, and then paste the result below"
    echo ""
    read -p "Paste your GitLab Personal Access Token here (then press enter/return): " TOKEN
    ACCESSFILE="$(getent passwd $USER | cut -d: -f6)/.gitlab.access"
    echo "${NETID,,}:${TOKEN}" > $ACCESSFILE
    chown $USER $ACCESSFILE
}

readToken() { # sets TOKEN
    # confirm access token is available
    if [[ ! -f "$(getent passwd $USER | cut -d: -f6)/.gitlab.access" ]]; then
	echo "No gitlab access token found, run \"cs400 init\" to create one"
	exit
    fi
    FILE="$(getent passwd $USER | cut -d: -f6)/.gitlab.access"
    TOKEN=$(cat $FILE)
    # confirm access token matches NETID entered by user
    if [[ ! ${TOKEN%%:*} = ${NETID,,} ]]; then	
	echo "NetID entered: $NETID does NOT match NetID stored with GitLab access token: ${TOKEN%%:*}.  Try running \"cs400 init\" to store your NetID along with a valid Gitlab Access Token in your account"
	exit
    fi
}

configLocalGitAccount() {
    echo "Copying gitlab name and email to local git profile."
    USERINFO=$(GET user)

    if [[ $EUID -eq 0 ]]; then
	su $USER -c "git config --global user.name \"$(echo $USERINFO | jq -r .name)\""
	su $USER -c "git config --global user.email \"$(echo $USERINFO | jq -r .email)\""
	su $USER -c "git config --global pull.rebase false"
    else
    	git config --global user.name "$(echo $USERINFO | jq .name)"
	git config --global user.email "$(echo $USERINFO | jq .email)"
	git config --global pull.rebase false
    fi    
}

addSelfToStudentGroup() {
    echo "Adding ${NETID} to their own subgroup on gitlab."
    curl https://cs400-web.cs.wisc.edu/gitlab/addToGroup.cgi?${NETID}
}

readActivityList() { # sets ACTIVITYLIST
    STUDENTGROUP="${COURSE}students/$NETID"
    ENCODED_STUDENTGROUP="${STUDENTGROUP//\//%2F}"
    GROUPID=$(GET groups/${ENCODED_STUDENTGROUP})
    if [[ $(echo $GROUPID | grep -c "id") < 1 ]]; then
	echo "Unable to access gitlab group id."
	exit 1
    else
	GROUPID=$(echo $GROUPID | jq .id)
	ACTIVITYLIST="$(GET groups/$GROUPID/projects | jq -r '.[].name')"
    fi
}

get() {
    chooseActivity # sets ACTIVITY
    URL="${GITLAB}${COURSE}students/${NETID,,}/${ACTIVITY}.git"
    git clone ${URL/https:\/\//https:\/\/${TOKEN}@} > $VERBOSE 2>&1
    
    echo "You should now have a new $ACTIVITY folder."
    echo "If not, try running \"cs400 get -v\" for more information about any problems that migth have prevented this from working"
}

chooseActivity() { # sets ACTIVITY
    select ACTIVITYCHOICE in ${ACTIVITYLIST[@]}; do
	if [[ -n $ACTIVITYCHOICE ]]; then
	    ACTIVITY="${ACTIVITYCHOICE}"
	    break
	else
	    echo "Please choose a valid number 1...${#ACTIVITYLIST[@]}"
	fi
    done
    echo "$ACTIVITY chosen."
}

confirmActivityWorkingDirectory() {
    ACTIVITY="${PWD##*/}"
    if [[ $(echo "$ACTIVITYLIST" | grep -ic "^${ACTIVITY}$") != 1 ]]; then
	echo "The folder you are running this script from does not appear to correspond to a CS400 activity.  This command should be run from a folder containing one of the following namnes: $ACTIVITYLIST"
	exit
    fi
    if [[ ! -d "./.git" ]]; then
	echo "You can only run this script from within a directory that was previously created by running the \"cs400 get\" command."
	exit
    fi
}

submit() {
    # update token in origin path in case token used to get has been deleted
    URL="${GITLAB}${COURSE}students/${NETID,,}/${ACTIVITY}.git"
    git remote set-url origin ${URL/https:\/\//https:\/\/$(cat ~/.gitlab.access)@}

    git stash > $VERBOSE
    git pull > $VERBOSE
    #rm -rf *
    #git checkout stash -- . > $VERBOSE
    #git stash drop > $VERBOSE
    git stash apply > $VERBOSE
    git add -A > $VERBOSE
    git commit -m "cs400 script submission from $(TZ='America/Chicago' date)" > $VERBOSE
    git push > $VERBOSE 2>&1
    if [[ $? -eq 0 ]]; then
	echo "Work sumbitted, use \"cs400 check\" to confirm submission time and check result of automated submission checks."
    else
	echo "Encountered a submission error.  Use \"cs400 submit -v\" to display more details about the cause of this error"
    fi
}

check() {
    STUDENTGROUP="${COURSE}students/$NETID"
    ENCODED_STUDENTGROUP="${STUDENTGROUP//\//%2F}"
    GROUPID=$(GET groups/${ENCODED_STUDENTGROUP} | jq .id)
    PROJECTID=$(GET groups/$GROUPID/projects?search=$ACTIVITY | jq ".[] | select(.name==\"${ACTIVITY}\") | .id")
    PIPEINFO=$(GET projects/$PROJECTID/jobs | jq first)
    echo "Status of automated submission checks from most recent submission $(echo $PIPEINFO | jq -r .created_at): $(echo $PIPEINFO | jq -r .status)"
    echo ""
    echo "Note that these submission checks are NOT used for grading, but are instead to help you detect some kinds of submission failures.  For more details about any problems detected, review the \"Executing step_script stage of the job script\" section on this webpage: $(echo $PIPEINFO | jq .web_url)"
}

restart() {
    read -p "Are you sure you want to overwrite the work in this directory: ${PWD} and restart? Enter yes or no: " CONFIRMCHOICE
    if [[ $CONFIRMCHOICE = yes ]]; then
	RESTARTCOMMIT=$(git log --grep="^restart from this commit$" -1 --pretty="format:%H")
	rm -rf *
	git checkout $RESTARTCOMMIT . > $VERBOSE
	# submit quitely (without running automated tests
	git add -A > $VERBOSE
	git commit -m "cs400 script (restart) submission from $(TZ='America/Chicago' date)" > $VERBOSE
	git push -o ci.skip > $VERBOSE 2>&1
    else
	echo "Assignment restart SAFELY ABORTED."
    fi
}

GET() {
    curl -s -H "PRIVATE-TOKEN: ${TOKEN##*:}" $GITLAB$API$1
}

main "$@"

