#!/usr/bin/env bash

# TODO: Count error and warning logs. Exit with 1 if at least one error encountered. Exit with 0 if a warning was encountered, and add a flag to consider it an error.

# Configure the script to exit when a command fails.
set -e

: ${SCRIPTS_ROOT:="${REPOSITORY_ROOT:?}"/scripts}
export SCRIPTS_ROOT
source "${SCRIPTS_ROOT:?}"/util.sh

# ===== CONSTANTS =====

: ${SELF:="$(basename $0)"}

source "${SCRIPTS_ROOT:?}"/constants.sh
: ${PROSE_POD_API_IMAGE_TAG:="${LOCAL_DOCKER_TAG:?}"}
export PROSE_POD_API_IMAGE_TAG
source "${SCRIPTS_ROOT:?}"/image-names.sh

INTEGRATION_TESTS_DIR="${REPOSITORY_ROOT:?}"/tests/integration
LOCAL_RUN_DIR="${REPOSITORY_ROOT:?}"/local-run
STEPCI_DIR="${INTEGRATION_TESTS_DIR:?}"/step-ci
: ${INTEGRATION_TEST_HOST:=http://127.0.0.1:8080}
export ENV_FILE="${INTEGRATION_TESTS_DIR:?}"/test.env
DNS_ZONES_DIR="${INTEGRATION_TESTS_DIR:?}"/dns-zones
export DNS_ZONE_FILE="${DNS_ZONES_DIR:?}"/working-static.zone
# NOTE: We don't want things like [stepci/stepci#239](https://github.com/stepci/stepci/issues/239)
#   to break the tests or the analytics server to slow down the tests execution.
export STEPCI_DISABLE_ANALYTICS=true
export SCENARIOS_DIR="${INTEGRATION_TESTS_DIR:?}"/scenarios
export SCENARIO_CONSTANTS_FILE="${SCENARIOS_DIR:?}"/constants.sh
BASE_SCENARIO_NAME=default
: ${COMPOSE_PROFILES:=test}
export COMPOSE_PROFILES

# ===== ARGUMENT PARSING =====

ARGS_=()
SKIPPED=()
for arg in "$@"; do
	case $arg in
		--api=*)
			export PROSE_POD_API_IMAGE_TAG="${arg#'--api='}"
			;;
		--server=*)
			export PROSE_POD_SERVER_IMAGE_TAG="${arg#'--server='}"
			;;
		+telemetry) COMPOSE_PROFILES+="${COMPOSE_PROFILES:+,}"telemetry ;;
		--help) die 'Unsupported' ;;
		--dry-run) export DRY_RUN=1 ;;
		--debug) export LOG_DEBUG=1 ;;
		--trace) export LOG_TRACE=1 ;;
		-*) SKIPPED+=("${arg#'-'}") ;;
		*) ARGS_+=("$arg") ;;
	esac
done
# Update command args so we can then list test names.
set -- "${ARGS_[@]}"
unset ARGS_

# ===== MAIN LOGIC =====

start() {
	if (( ${SKIP_POD_START:-0} )); then
		trace "Not starting the Prose Pod ($(format_code "SKIP_POD_START=${SKIP_POD_START:?}"))."
	else
		trace 'Starting the Prose Pod…'

		SCENARIO_NAME="${BASE_SCENARIO_NAME:?}-$(date +%s)"

		task local:run -- --detach --api=local \
			--scenario="${BASE_SCENARIO_NAME:?}" \
			--ephemeral --ephemeral-name="${SCENARIO_NAME:?}"

		wait_until_api_running "${INTEGRATION_TEST_HOST:?}"

		if [ -n "${prose_config_dir-}" ]; then
			# Update configuration file.
			edo cp -f "${prose_config_dir:?}"/* "${SCENARIOS_DIR:?}"/"${SCENARIO_NAME:?}"/prose-config/*

			# Reload APIs with new configuration file.
			ADMIN_TOKEN="$(xh POST "${INTEGRATION_TEST_HOST:?}"/v1/login -a 'pauline.collins@test.local:demo' -b | jq -r '.token')"
			[ "${ADMIN_TOKEN:?}" != 'null' ] || die 'Failed logging admin in'
			edo log_as_trace_ xh POST "${INTEGRATION_TEST_HOST:?}"/reload -A bearer -a "${ADMIN_TOKEN:?}" --meta

			wait_until_api_running "${INTEGRATION_TEST_HOST:?}"
		fi
	fi
}

stop() {
	if (( ${SKIP_POD_STOP:-0} )); then
		trace "Not stopping the Prose Pod ($(format_code "SKIP_POD_STOP=${SKIP_POD_STOP:?}"))."
	else
		trace 'Stopping the Prose Pod…'
		task local:stop
	fi
}

source "${INTEGRATION_TESTS_DIR:?}"/util.sh

on_exit() {
	rc=$?
	if [ "$rc" -ne 0 ]; then
		error "Script failed with exit code $rc"
		print_test_logs
	fi
}

trap on_exit EXIT

stepci_run() {
	local test_file=${1:?}
	local config_options=${2-test}

	info "$(fg_blue "$(for _ in $(seq 72); do printf "="; done)")"
	info "$(fg_blue "Running test '$(sed "s#${STEPCI_DIR:?}/##" <<< "${test_file}")' with config '${config_options}'…")"
	info "$(fg_blue "$(for _ in $(seq 72); do printf "="; done)")"

	export prose_config_dir="${INTEGRATION_TESTS_DIR:?}/prose-config-${config_options:?}"
	[ -d "${prose_config_dir:?}" ] || die "Directory $(format_url "${prose_config_dir:?}") doesn't exist."

	if [ "${LATE_RELOAD_CONFIG:-0}" -eq 1 ]; then
		unset PROSE_CONFIG_DIR
	else
		export PROSE_CONFIG_DIR="${prose_config_dir:?}"
		unset prose_config_dir
	fi

	# NOTE: We have to `cd $STEPCI_DIR` because transitive `$ref`s are not processed correctly otherwise.
	start && \
	{ (cd "${STEPCI_DIR:?}" && edo stepci run "${test_file#"${STEPCI_DIR:?}/"}" --env host="${INTEGRATION_TEST_HOST:?}") \
	&& { stop || die 'Could not stop properly.'; } || abort; }
}

if [ "$#" -eq 0 ]; then
	info "No test file provided. Will use all $(format_code '*.yaml') files in $(format_url "${STEPCI_DIR:?}")."
	# WARN: Spaces in `*.yaml` files will break.
	set -- \
		$(cd "${STEPCI_DIR:?}"; find . -type f -name '*.yaml' ! -name 'env.yaml' | sed -E "s/\.\/(.+)\.yaml$/\1/") \
		$(cd "${INTEGRATION_TESTS_DIR:?}"; find . -type f -name 'test-*' | sed -E "s/\.\/test-(.+)$/\1/")
fi

info "Will run tests on $(format_url ${INTEGRATION_TEST_HOST:?})."

# NOTE: Some tests need a different `PROSE_CONFIG_DIR` or `DNS_ZONE_FILE`.
#   Special cases are handled here.
for arg in "$@"; do
	if in_array SKIPPED "$arg"; then
		warn "Skipping test $(format_code "$arg") (marked to skip)."
		continue
	fi

	if [[ -f "${INTEGRATION_TESTS_DIR:?}"/test-"$arg" ]]; then
		"${INTEGRATION_TESTS_DIR:?}"/test-"$arg"
		continue
	fi

	test_file="${STEPCI_DIR:?}/${arg:?}.yaml"

	if ! [ -f "$test_file" ]; then
		error "$(format_url "$test_file") not found, skipping."
		continue
	fi

	case $arg in
		*dns-configured-correctly-dynamic)
			DNS_ZONE_FILE="${DNS_ZONES_DIR:?}"/working-dynamic.zone stepci_run "$test_file" ;;
		*dns-configured-correctly-static)
			DNS_ZONE_FILE="${DNS_ZONES_DIR:?}"/working-static.zone stepci_run "$test_file" 'static-address' ;;
		auth-expired)
			LATE_RELOAD_CONFIG=1 stepci_run "$test_file" 'tokens-expired' ;;
		init)
			SCENARIO_NAME=fresh BASE_SCENARIOS_DIR="${LOCAL_RUN_DIR:?}"/scenarios stepci_run "$test_file" ;;
		*)
			stepci_run "$test_file" ;;
	esac
done
