#! /usr/bin/env bash

repository="$1"
workdir="$2"
fossilCIDir="$3"
if [ -z "${repository}" -o -z "${workdir}" ]; then
	echo "Usage: autobuild <repository> <workdir> [<fossil-ci-dir>]" >&2

	exit 1
fi

if [ -z "${fossilCIDir}" ]; then
	fossilCIDir='.fossil-ci'
fi

# 0. Resolve paths
repository="$(cd "$(dirname "${repository}")" && echo "$(pwd)/$(basename "${repository}")")" || exit 1
workdir="$(mkdir -p "${workdir}" && cd "${workdir}" && pwd)" || exit 1

# 1. Register cleanup
tmpdir=''
function cleanup() {
	if [ -n "${tmpdir}" ]; then
		rm -rf "${tmpdir}"
	fi
}
trap cleanup EXIT

# 2. Setup a sane environment
## 2.a. Abort on errors
set -e

## 2.b. Universal timezone
export TZ=UTC

## 2.c. Basic locale
unset $(locale | cut -f 1 -d =)

## 2.d. Sane umask
umask 022

# 3. Update the Fossil repository
fossil config -R "${repository}" pull all >/dev/null 2>/dev/null || :
fossil sync -R "${repository}" >/dev/null 2>/dev/null || :

# 4. Get a list of branches
branches=( $(fossil branch -R "${repository}" list) )

# 5. Get Fossil CI configuration from the trunk branch
## 5.a. Set default config
### 5.a.i. Set default variables
excludedBranches=()
includedBranches=('')
buildCommands=('./autogen.sh || :' ./configure make)
initCommands=()
postCommands=()
branchPostCommands=()
testCommands=()
builderID=''
projectName="$(fossil info -R "${repository}" | awk '/^project-name:/{ sub(/^project-name: */, ""); gsub(/ /, ""); print; }')"
tagSuffix=''
tagPrefix=''
# tagOmit='all|pass|redundant|none'
tagOmit='none'
# buildResultsUpload='fail|all|none'
buildResultsUpload='fail'
# testResultsUpload='fail|all|none'
testResultsUpload='fail'

### 5.a.ii. Default functions
function uploadBuildResults() {
	### XXX:TODO
	:
}

function uploadTestResults() {
	### XXX:TODO
	:
}

function uploadBuildArtifacts() {
	### XXX:TODO
	:
}

function fossilSetWikiPage() {
	### XXX:TODO
	:
}

function fossilUploadUV() {
	### XXX:TODO
	:
}

## 5.b. Read config
config="$(fossil cat -R "${repository}" -r trunk "${fossilCIDir}/config" 2>/dev/null)" || :

## 5.c Load config
if [ -f  ~/.fossil-ci/config ]; then
	. ~/.fossil-ci/config
fi

eval "${config}"

if [ -f ~/.fossil-ci/"${projectName}"/config ]; then
	. ~/.fossil-ci/"${projectName}"/config
fi

# 6. Perform any configured initialization
for cmd in "${initCommands[@]}"; do
	eval "${cmd}" >/dev/null 2>/dev/null || :
done

# 7. For each branch, attempt to build
for branch in "${branches[@]}"; do
	## 7.a. Only process specific branches
	ignoreBranch='1'
	for testBranch in "${includedBranches[@]}"; do
		if echo "${branch}" | grep "${testBranch}" >/dev/null; then
			ignoreBranch='0'

			break
		fi
	done

	for testBranch in "${excludedBranches[@]}"; do
		if echo "${branch}" | grep "${testBranch}" >/dev/null; then
			ignoreBranch='1'

			break
		fi
	done

	if [ "${ignoreBranch}" = '1' ]; then
		continue
	fi

	## 7.b. Find the branch working directory
	branchdir="$(echo "${branch}" | sed 's@[^A-Za-z0-9-]@_@g')"
	builddir="${workdir}/build-output/branch-${branchdir}"
	branchdir="${workdir}/working-copies/branch-${branchdir}"
	mkdir -p "${branchdir}"

	## 7.c. Determine current checkout ID
	checkout="$(fossil info -R "${repository}" "${branch}" | awk '/^uuid:/{ print $3 "T" $4 "-" $2 }')"
	builddir="${builddir}/checkout-${checkout}"

	## 7.d. Determine if build even needs to occur
	if [ -d "${builddir}" ]; then
		continue
	fi
	mkdir -p "${builddir}"

	## 7.e. Check-out or update the branch
	(
		cd "${branchdir}" || exit 1

		if [ ! -f '.fslckout' ]; then
			fossil open "${repository}" "${branch}" --nested
		else
			fossil update "${branch}"
		fi
	) > "${builddir}/update.log" 2>&1 || continue

	## 7.f. Build and log the results, if there are any
	build_pass='1'
	(
		cd "${branchdir}" || exit 1

		for cmd in "${buildCommands[@]}"; do
			( eval "set -x; ${cmd}" ) || exit 1
		done
	) > "${builddir}/build.log" 2>&1 || build_pass='0'

	### 7.g. Test the branch
	tests_pass='-1'
	if [ "${build_pass}" = '1' ]; then
		tests_pass='1'
		(
			cd "${branchdir}" || exit 1

			for cmd in "${testCommands[@]}"; do
				( eval "set -x; ${cmd}" ) || exit 1
			done
		) > "${builddir}/test.log" 2>&1 || tests_pass='0'
	fi

	### 7.h. Tag the branch with
	tagsToAdd=()
	if [ "${build_pass}" = '1' ]; then
		case "${tagOmit}" in
			all|pass|redundant)
				;;
			*)
				tagsToAdd=("${tagsToAdd[@]}" build-pass)
				;;
		esac

		if [ "${tests_pass}" = '1' ]; then
			case "${tagOmit}" in
				all|pass)
					;;
				*)
					tagsToAdd=("${tagsToAdd[@]}" tests-pass)
					;;
			esac
		else
			tagsToAdd=("${tagsToAdd[@]}" tests-fail)
		fi
	else
		tagsToAdd=("${tagsToAdd[@]}" build-fail)
	fi

	tagsToAddOpts=()
	for tag in "${tagsToAdd[@]}"; do
		tagsToAddOpts=("${tagsToAddOpts[@]}" --tag "${tagPrefix}${tag}${tagSuffix}")
	done

	fossil amend -R "${repository}" "${branch}" "${tagsToAddOpts[@]}" > "${builddir}/update.log" 2>&1

	### 7.i. Upload the logs somewhere if requested
	uploadBuildResults='0'
	case "${buildResultsUpload}-${build_pass}" in
		all-0|all-1|fail-0|pass-1)
			uploadBuildResults='1'
			;;
	esac

	uploadTestResults='0'
	case "${buildResultsUpload}-${tests_pass}" in
		all-0|all-1|fail-0|pass-1)
			uploadTestResults='1'
			;;
	esac

	if [ "${uploadBuildResults}" ]; then
		uploadBuildResults "${branch}" "${checkout}" "${builddir}/build.log" || :
	fi

	if [ "${uploadBuildResults}" ]; then
		uploadTestResults "${branch}" "${checkout}" "${builddir}/test.log" || :
	fi

	### 7.j. Upload build artifacts somewhere if requested
	uploadBuildArtifacts "${branch}" "${checkout}" "${branchdir}" || :

	### 7.k. Get a list of tags
	tags=( $(fossil tag -R "${repository}" list "${branch}") )

	# 8. Perform post-build work (e.g., for release engineering)
	(
		cd "${branchdir}" || exit 1
		for cmd in "${branchPostCommands[@]}"; do
			( eval "set -x; ${cmd}" ) || exit 1
		done
	) > "${builddir}/post.log" 2>&1 || :
done

# 9. Clean up any branches that no longer exist
## XXX:TODO
