#!/bin/bash

if [ -z "$(git remote)" ] ; then
	# Ignore non-public repositories
	exit 0
fi

. ~/.bash.d/identity

# Get the list of non-publish branches
public_branches=()
private_branches=()
for branch in $(git branch | tr -d '*') ; do
	case "$branch" in
		(github)
			private_branches+=("$branch")
		;;
		(githubgithub)
			private_branches+=("$branch")
		;;
		*)
			if publish="$(git config --bool "branch.$branch.publish")" && [ "x$publish" = xfalse ] ; then
				private_branches+=("$branch")
			else
				public_branches+=("$branch")
			fi
		;;
	esac
done

# Check if there are any local commits
shopt -s lastpipe
git rev-list --count --branches --not --remotes "${private_branches[@]}" |
read -r local_commits

# Decide if the remote repo needs publishing or deleting
if [ "$local_commits" -eq 0 ] ; then
	action=delete
else
	action=publish
fi

set_variables () {
	case "$remote" in
		https://github.com/*|ssh://github.com/*|git@github.com:*)
			user="$(git config publish.github.com.user)"
			project=${remote#https://github.com/}
			project=${project#ssh://github.com/}
			project=${project#git@github.com:}
			project=${project%.git}
			project=${project%/}
			repo=${project#*/}
			slug=$user/$repo
			remote=ssh://github.com/$slug.git
			type=github
		;;
		https://salsa.debian.org/*|ssh://salsa.debian.org/*|git@salsa.debian.org:*)
			user="$(git config publish.salsa.debian.org.user)"
			project=${remote#https://salsa.debian.org/}
			project=${project#ssh://salsa.debian.org/}
			project=${project#git@salsa.debian.org:}
			project=${project%.git}
			project=${project%/}
			repo=${project#*/}
			slug=$user/$repo
			remote=git@salsa.debian.org:$slug.git
			type=gitlab
		;;
		https://gitlab.softwareheritage.org/*|ssh://gitlab.softwareheritage.org/*|git@gitlab.softwareheritage.org:*)
			user="$(git config publish.gitlab.softwareheritage.org.user)"
			project=${remote#https://gitlab.softwareheritage.org/}
			project=${project#ssh://gitlab.softwareheritage.org/}
			project=${project#git@gitlab.softwareheritage.org:}
			project=${project%.git}
			project=${project%/}
			repo=${project#*/}
			slug=$user/$repo
			remote=git@gitlab.softwareheritage.org:$slug.git
			type=gitlab
		;;
		ssh://git@git2.debian.org/*)
			user="$(git config publish.git2.debian.org.user)"
			project=${remote#ssh://git@git2.debian.org/}
			project=${project%.git}
			project=${project%/}
			project=${project#*/}
			repo=$project
			project=dsa-team/mirror/$project
			slug=$user/$repo
			remote=git@salsa.debian.org:$slug.git
			type=gitlab
		;;
		https://gitlab.com/*|ssh://gitlab.com/*|git@gitlab.com:*)
			user="$(git config publish.gitlab.com.user)"
			project=${remote#https://gitlab.com/}
			project=${project#ssh://gitlab.com/}
			project=${project#git@gitlab.com:}
			project=${project%.git}
			project=${project%/}
			repo=${project#*/}
			slug=$user/$repo
			remote=git@gitlab.com:$slug.git
			type=gitlab
		;;
		https://bitbucket.org/*|git@bitbucket.org:*)
			user="$(git config publish.bitbucket.org.user)"
			project=${remote#https://bitbucket.org/}
			project=${project#ssh://bitbucket.org/}
			project=${project#git@bitbucket.org:}
			project=${project%.git}
			project=${project%/}
			repo=${project#*/}
			slug=$user/$repo
			remote=git@bitbucket.org:$slug.git
			type=bitbucket
		;;
	esac
}

if ! remote="$(git config publish.remote)" && [ $action = publish ] && [ "x$AUTOPUBLISH" != x1 ] ; then
	branch="$(git rev-parse --abbrev-ref HEAD)"
	remote="$(git config "branch.$branch.remote")"
	remote="$(git remote get-url "$remote")"
	set_variables

	# Ask where to publish, using the fork location as the default
	read -p 'Enter URL to repo to publish in: ' -r -e -i "$remote" remote

	if [ -n "$remote" ] ; then
		case "$type" in
			github)
				echo "Forking to $remote..."
				hub fork --no-remote &&
				git config publish.remote "$remote"
			;;
			gitlab)
				echo "Forking to $remote..."
				gitlab-api-v4 fork-project "$project" &&
				git config publish.remote "$remote"
			;;
			*)
				echo "Please fork $remote manually"
				echo "Please run this afterwards (fix the URL): git config publish.remote $remote "
				if [ "x$AUTOPUBLISH" != x1 ] ; then
					echo "Please exit the shell afterwards"
					bash -i
				fi
			;;
		esac
	fi
fi

if [ -n "$remote" ] && [ -z "$NO_MIRROR" ]; then
	if [ -z "$type" ] ; then
		set_variables
	fi

	if true ; then
		publish_branches="$(git config --bool publish.branches)"
	else
		publish_branches=false
	fi

	if true ; then
		publish_tags="$(git config --bool publish.tags)"
	else
		publish_tags=false
	fi

	# Publish/delete only when user chooses to do so
	if [ $action = publish ] ; then
		if [ "${#private_branches[@]}" -eq 0 ]; then
			branch_push=(--all "$remote")
			# --prune --all does it for us
			delete_refs=false
		else
			branch_push=("$remote")
			for branch in "${public_branches[@]}" ; do
				branch_push+=("$branch:$branch")
			done
			# FIXME:
			# --prune does nothing with a refspec
			# so delete all refs before pushing
			delete_refs=true
		fi
		# --all and --tags are incompatible so
		# these have to be done separately :(
		{
			if [ "$(git config --bool publish.unprotect)" != false ] ; then
				case "$type" in
					gitlab)
						echo -n Unprotecting...
						gitlab-api-v4 protected-branches "$slug" | jq -r .[].name | xargs -r -d '\n' -n1 gitlab-api-v4 unprotect-branch "$slug"
						gitlab-api-v4 protected-tags "$slug" | jq -r .[].name | xargs -r -d '\n' -n1 gitlab-api-v4 unprotect-tag "$slug"
						echo
					;;
				esac
			fi
			ci=$(git config --bool publish.ci || echo false)
			case "$type" in
				gitlab)
					echo -n Updating CI...
					gitlab-api-v4 edit-project "$slug" jobs_enabled:"$ci" > /dev/null
					echo
				;;
			esac
			if [ "$delete_refs" != false ] ; then
				git ls-remote "$remote" | cut -f2 | grep -v '\^{}$' | grep -v '^HEAD$' | xargs -d '\n' git push --delete "$remote"
			fi
			if [ "$publish_branches" != false ] ; then
				git push --force --prune "${branch_push[@]}"
			fi
			if [ "$publish_tags" != false ] ; then
				git push --force --prune --tags "$remote"
			fi
		} |& grep -vF 'Everything up-to-date' || true
	elif [ $action = delete ] ; then
		case "$type" in
			github)
				hub delete "$slug" &&
				git config --unset publish.remote
			;;
			gitlab)
				gitlab-api-v4 delete-project "$slug" &&
				git config --unset publish.remote
			;;
			*)
				echo "Please delete repo $remote manually"
				echo "Please run this afterwards: git config --unset publish.remote"
				if [ "x$AUTOPUBLISH" != x1 ] ; then
					echo "Please exit the shell afterwards"
					bash -i
				fi
			;;
		esac
	else
		echo "Please complete action $action manually for $remote"
		if [ "x$AUTOPUBLISH" != x1 ] ; then
			echo "Please exit the shell afterwards"
			bash -i
		fi
	fi
fi
