#!/bin/bash
#
# SPDX-License-Identifier: GPL-3.0-or-later

[[ -z ${DEVTOOLS_INCLUDE_REPO_CONFIGURE_SH:-} ]] || return 0
DEVTOOLS_INCLUDE_REPO_CONFIGURE_SH=1

_DEVTOOLS_LIBRARY_DIR=${_DEVTOOLS_LIBRARY_DIR:-/usr/local/share/devtools-git-poc}
# shellcheck source=src/lib/common.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/common.sh
# shellcheck source=src/lib/api/gitlab.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/api/gitlab.sh

source /usr/share/makepkg/util/config.sh
source /usr/share/makepkg/util/message.sh

set -e


pkgctl_repo_configure_usage() {
	local -r COMMAND=${_DEVTOOLS_COMMAND:-${BASH_SOURCE[0]##*/}}
	cat <<- _EOF_
		Usage: ${COMMAND} [OPTIONS] [PATH]...

		Configure Git packaging repositories according to distro specs and
		makepkg.conf settings.

		Git author information and the used signing key is set up from
		makepkg.conf read from any valid location like /etc or XDG_CONFIG_HOME.

		The remote protocol is automatically determined from the author email
		address by choosing SSH for all official packager identities and
		read-only HTTPS otherwise.

		OPTIONS
		    -h, --help           Show this help text

		EXAMPLES
		    $ ${COMMAND} configure *
_EOF_
}

get_packager_name() {
	local packager=$1
	local packager_pattern="(.+) <(.+@.+)>"
	local name

	if [[ ! $packager =~ $packager_pattern ]]; then
		return 1
	fi

	name=$(echo "${packager}"|sed -E "s/${packager_pattern}/\1/")
	printf "%s" "${name}"
}

get_packager_email() {
	local packager=$1
	local packager_pattern="(.+) <(.+@.+)>"
	local email

	if [[ ! $packager =~ $packager_pattern ]]; then
		return 1
	fi

	email=$(echo "${packager}"|sed -E "s/${packager_pattern}/\2/")
	printf "%s" "${email}"
}

is_packager_name_valid() {
	local packager_name=$1
	if [[ -z ${packager_name} ]]; then
		return 1
	elif [[ ${packager_name} == "John Doe" ]]; then
		return 1
	elif [[ ${packager_name} == "Unknown Packager" ]]; then
		return 1
	fi
	return 0
}

is_packager_email_official() {
	local packager_email=$1
	if [[ -z ${packager_email} ]]; then
		return 1
	elif [[ $packager_email =~ .+@archlinux.org ]]; then
		return 0
	fi
	return 1
}

pkgctl_repo_configure() {
	# options
	local GIT_REPO_BASE_URL=${GIT_PACKAGING_URL_HTTPS}
	local official=0
	local proto=https
	local paths=()

	# variables
	local path realpath pkgbase remote_url project_path
	local PACKAGER GPGKEY packager_name packager_email

	while (( $# )); do
		case $1 in
			-h|--help)
				pkgctl_repo_configure_usage
				exit 0
				;;
			--)
				shift
				break
				;;
			-*)
				die "invalid argument: %s" "$1"
				;;
			*)
				paths=("$@")
				break
				;;
		esac
	done

	# check if invoked without any path from within a packaging repo
	if (( ${#paths[@]} == 0 )); then
		if [[ -f PKGBUILD ]]; then
			paths=(".")
		else
			pkgctl_repo_configure_usage
			exit 1
		fi
	fi

	# Load makepkg.conf variables to be available for packager identity
	msg "Collecting packager identity from makepkg.conf"
	# shellcheck disable=2119
	load_makepkg_config
	if [[ -n ${PACKAGER} ]]; then
		if ! packager_name=$(get_packager_name "${PACKAGER}") || \
		   ! packager_email=$(get_packager_email "${PACKAGER}"); then
			die "invalid PACKAGER format '${PACKAGER}' in makepkg.conf"
		fi
		if ! is_packager_name_valid "${packager_name}"; then
			die "invalid PACKAGER '${PACKAGER}' in makepkg.conf"
		fi
		if is_packager_email_official "${packager_email}"; then
			official=1
			proto=ssh
			GIT_REPO_BASE_URL=${GIT_PACKAGING_URL_SSH}
		fi
	fi

	msg2 "name    : ${packager_name:-${YELLOW}undefined${ALL_OFF}}"
	msg2 "email   : ${packager_email:-${YELLOW}undefined${ALL_OFF}}"
	msg2 "gpg-key : ${GPGKEY:-${YELLOW}undefined${ALL_OFF}}"
	if [[ ${proto} == ssh ]]; then
		msg2 "protocol: ${GREEN}${proto}${ALL_OFF}"
	else
		msg2 "protocol: ${YELLOW}${proto}${ALL_OFF}"
	fi

	for path in "${paths[@]}"; do
		if ! realpath=$(realpath -e "${path}"); then
			error "No such directory: ${path}"
			continue
		fi

		pkgbase=$(basename "${realpath}")
		pkgbase=${pkgbase%.git}
		msg "Configuring ${pkgbase}"

		if [[ ! -d "${path}/.git" ]]; then
			error "Not a Git repository: ${path}"
			continue
		fi

		pushd "${path}" >/dev/null

		project_path=$(gitlab_project_name_to_path "${pkgbase}")
		remote_url="${GIT_REPO_BASE_URL}/${project_path}.git"
		if ! git remote add origin "${remote_url}" &>/dev/null; then
			git remote set-url origin "${remote_url}"
		fi

		# move the master branch to main
		if [[ $(git symbolic-ref --short HEAD) == master ]]; then
			git branch --move main
			git config branch.main.merge refs/heads/main
		fi

		git config devtools.version "${GIT_REPO_SPEC_VERSION}"
		git config pull.rebase true
		git config branch.autoSetupRebase always
		git config branch.main.remote origin
		git config branch.main.rebase true

		git config transfer.fsckobjects true
		git config fetch.fsckobjects true
		git config receive.fsckobjects true

		# setup author identity
		if [[ -n ${packager_name} ]]; then
			git config user.name "${packager_name}"
			git config user.email "${packager_email}"
		fi

		# force gpg for official packagers
		if (( official )); then
			git config commit.gpgsign true
		fi

		# set custom pgp key from makepkg.conf
		if [[ -n $GPGKEY ]]; then
			git config commit.gpgsign true
			git config user.signingKey "${GPGKEY}"
		fi

		if ! git ls-remote origin &>/dev/null; then
			warning "configured remote origin may not exist, run:"
			msg2 "pkgctl repo create ${pkgbase}"
		fi

		popd >/dev/null
	done
}
