#!/bin/zsh

# Manage Aerospike CE/EE branch pairs: create a set of branches, optionally with
# a starting point; checkout a set of branches; fetch remotes; remove a set of
# worktrees and their branches.
#
# In case of checkout or create, Emacs project will be set up and Aerospike
# server built in EE flavor.
#
# Environment prerequisites:
# - ASD_BRANCHES: the root directory of feature branches
# - ASD_MASTER: the root directory of AS EE and CE master branches
# - LINUX_SYSROOT (only on macOS): the sysroot directory with /usr/include from
#   a Linux installation
#

set -eu

readonly COMMAND="${1-UNDEFINED}"

if [[ "$COMMAND" != "create" && "$COMMAND" != "checkout" &&
	"$COMMAND" != "fetch" && "$COMMAND" != "init" &&
	"$COMMAND" != "pull" && "$COMMAND" != "push" && "$COMMAND" != "rm" &&
	"$COMMAND" != "status" && "$COMMAND" != "worktree" &&
	"$COMMAND" != "rsync" || "$COMMAND" == "UNDEFINED" ]]; then
	echo "Usage: $0 checkout branch"
	echo "       $0 create branch starting_point [ee_starting_point]"
	echo "       $0 fetch"
	echo "       $0 init branch"
	echo "       $0 pull"
	echo "       $0 push"
	echo "       $0 rm branch"
	echo "       $0 rsync branch"
	echo "       $0 status"
	echo "       $0 worktree prune"
	exit 1
fi

readonly UNAME_OUT="$(uname -s)"
readonly SUPPORT_FILE_DIR="$HOME/dotfiles/aerospike/aerospike"

function do_master_command() {
	pushd "$EE_MASTER" || exit 1
	eval "$cmd"
	popd || exit 1

	pushd "$CE_MASTER" || exit 1
	eval "$cmd"
	popd || exit 1
}

function do_local_command() {
	pushd "ee" || exit 1
	eval "$cmd"
	popd || exit 1

	pushd "ce" || exit 1
	eval "$cmd"
	popd || exit 1
}

function do_worktree_prune() {
	cmd="git worktree prune"
	do_master_command
}

function do_rm() {
	rm -rf "$BRANCH_ROOT" || exit 1

	do_worktree_prune

	cmd="git branch -d $BRANCH"
	do_master_command
}

function do_status() {
	cmd="git status"
	do_local_command
}

function do_init() {
	if [[ "$UNAME_OUT" == "Linux" ]]; then
		rm -f compile_flags.txt
	fi
	ln -sf "$SUPPORT_FILE_DIR/.clang-format" .
	ln -sf "$SUPPORT_FILE_DIR/.clangd" .
	cp "$SUPPORT_FILE_DIR/asd-.dir-locals.el" .dir-locals.el
	ln -sf "$SUPPORT_FILE_DIR/asd-Makefile" Makefile
	ln -sf "$SUPPORT_FILE_DIR/CPPLINT.cfg" CPPLINT.cfg
	if [[ "$UNAME_OUT" != "Linux" ]]; then
		cp "$SUPPORT_FILE_DIR/compile_flags.txt.in" compile_flags.txt
		sed -i.bak "s:\$LINUX_SYSROOT:$LINUX_SYSROOT:g" compile_flags.txt
		rm compile_flags.txt.bak
	fi
	touch .projectile
	if [[ "$UNAME_OUT" == "Linux" ]]; then
		make build
	fi
}

# Zero-arg commands

if [[ "$COMMAND" == "pull" ]]; then
	cmd="git pull --all --ff-only --recurse-submodules=yes \
         && git submodule update --recursive"
	do_local_command
	exit 0
fi

if [[ "$COMMAND" == "push" ]]; then
	cmd="git push"
	do_local_command
	exit 0
fi

if [[ "$COMMAND" == "status" ]]; then
	cmd="git status"
	do_local_command
	exit 0
fi

readonly CE_MASTER="$ASD_MASTER/ce"
readonly EE_MASTER="$ASD_MASTER/ee"

if [[ "$COMMAND" == "fetch" ]]; then
	cmd="git fetch --all -p --recurse-submodules=yes -j 5"
	do_master_command
	exit 0
fi

pushd "$ASD_BRANCHES" || exit 1

# "worktree prune" where "prune" is not an arg but a subcommand
if [[ "$COMMAND" == "worktree" && "$2" == "prune" ]]; then
	do_worktree_prune
	exit 0
fi

# One or more-arg commands

readonly BRANCH="$2"

if [[ "$COMMAND" == "rm" ]]; then
	do_rm
	popd || exit 0
	exit 0
fi

if [[ "$COMMAND" == "init" ]]; then
	pushd "$BRANCH" || exit 1
	do_init
	popd || exit 1
	exit 0
fi

if [[ "$COMMAND" == "rsync" ]]; then
	readonly BRANCH_ROOT="$ASD_BRANCHES/$BRANCH"
	rsync -rzui "$BRANCH_ROOT" "$LINUX_VM:$LINUX_ASD_BRANCHES"
	exit 0
fi

if [[ "$COMMAND" == "create" && $# -gt 2 ]]; then
	readonly START_POINT="$3"
	if [[ $# -gt 3 ]]; then
		readonly EE_START_POINT="$4"
	else
		readonly EE_START_POINT="$START_POINT"
	fi
fi

mkdir "$BRANCH"

pushd "$EE_MASTER" || exit 1
# Support checking out CE-only branches
if [[ "$COMMAND" == "create" || -z $(git branch --list "$BRANCH") ]]; then
	git worktree add "$BRANCH_ROOT/ee" -b "$BRANCH" \
		${EE_START_POINT:+"$EE_START_POINT"}
else
	git worktree add "$BRANCH_ROOT/ee" "$BRANCH"
fi
popd || exit 1

pushd "$CE_MASTER" || exit 1
if [[ "$COMMAND" == "create" ]]; then
	git worktree add "$BRANCH_ROOT/ce" -b "$BRANCH" \
		${START_POINT:+"$START_POINT"}
else
	git worktree add "$BRANCH_ROOT/ce" "$BRANCH"
fi
popd || exit 1

pushd "$BRANCH/ee" || exit 1
if [[ "$COMMAND" == "create" ]]; then
	git branch -u "origin/$BRANCH"
fi
git submodule update --init --recursive
if [[ "$UNAME_OUT" == "Linux" ]]; then
	ln -sf "../ce/compile_commands.json" .
fi
popd || exit 1

pushd "$BRANCH/ce" || exit 1
if [[ "$COMMAND" == "create" ]]; then
	git branch -u "origin/$BRANCH"
fi
git submodule update --init --recursive
popd || exit 1

pushd "$BRANCH" || exit 1
do_init
popd || exit 0

popd || exit 0
