#!/usr/bin/env bash

set -eu
set -o pipefail

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

INTEGRATION_TESTS_DIR="${REPOSITORY_ROOT:?}"/tests/integration
LOCAL_RUN_DIR="${REPOSITORY_ROOT:?}"/local-run
LOCAL_RUN_SCRIPTS="${LOCAL_RUN_DIR:?}"/scripts
BASE_SCENARIO_NAME=default
: ${INTEGRATION_TEST_HOST:=http://127.0.0.1:8080}
: ${PROSE_POD_API_IMAGE_TAG:=local}
SCENARIO_NAME="${BASE_SCENARIO_NAME:?}-$(date +%s)"

# Unset `PROSE_CONFIG_FILE` so it’s not overwritten by the factory reset.
unset PROSE_CONFIG_DIR PROSE_CONFIG_FILE
# Compute dynamic variables.
source "${LOCAL_RUN_SCRIPTS:?}"/scenario-files.sh

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

info "$(fg_blue "$(for _ in $(seq 72); do printf "="; done)")"
info "$(fg_blue "Running test 'factory-reset'…")"
info "$(fg_blue "$(for _ in $(seq 72); do printf "="; done)")"

info 'Starting the test API (already populated with data)…'
edo task local:run -- --detach \
	--api="${PROSE_POD_API_IMAGE_TAG:?}" \
	--scenario="${BASE_SCENARIO_NAME:?}" \
	--ephemeral --ephemeral-name="${SCENARIO_NAME:?}"

# Wait a bit to make sure the API is ready (e.g. has run migrations).
sleep 1

info Logging an admin in…
TOKEN="$(xh POST -I "${INTEGRATION_TEST_HOST:?}"/v1/login \
	-a 'pauline.collins@test.local:demo' \
	content-type: \
	| jq -r '.token')"
[ -n "${TOKEN-}" ] && [ "${TOKEN:?}" != null ] || abort

info Getting the factory reset token…
CONFIRMATION="$(xh DELETE -I "${INTEGRATION_TEST_HOST:?}" \
	-A bearer -a "${TOKEN:?}" \
	password=demo \
	| jq -r '.confirmation')"
[ -n "${CONFIRMATION-}" ] && [ "${CONFIRMATION:?}" != null ] || abort

info Performing the factory reset…
edo xh DELETE -Iq "${INTEGRATION_TEST_HOST:?}" \
	-A bearer -a "${TOKEN:?}" \
	confirmation="${CONFIRMATION:?}" || abort

info Checking if factory reset deleted everything…

# NOTE: After a factory reset, the Prose Pod Server API restarts Prosody
#   with a minimal configuration so it can still interact with it.
#   This makes Prosody recreate some data, but it’s clear it has nothing
#   to do with the previous Prose Pod instance.
FRESH_PROSODY_DATA=''
if [ -n "$(ls -A1 "${VAR_LIB_PROSODY_DIR:?}" | grep -v -E "^(${FRESH_PROSODY_DATA:-})$")" ]; then
	die "Prosody still contains data ($(format_url "${VAR_LIB_PROSODY_DIR:?}") isn’t empty)."
fi
success Prosody data deleted

if [ -n "$(ls -A1 "${ETC_PROSODY_DIR:?}")" ]; then
	die "Prosody still contains config ($(format_url "${ETC_PROSODY_DIR:?}") isn’t empty)."
fi
success Prosody config reset

PROSODY_CERTS_DIR="${ETC_PROSODY_DIR:?}"/certs
if [ -d "${PROSODY_CERTS_DIR:?}" ] && [ -n "$(ls -A "${PROSODY_CERTS_DIR:?}")" ]; then
	die "Prosody still contains certificates ($(format_url "${PROSODY_CERTS_DIR:?}") isn’t empty)."
fi
success Prosody certs directory is empty

# Wait for the API to flush data to SQLite.
sleep 1

# NOTE: We can’t just check if the file is empty as the API runs migrations when it restarts.
#   By checking that important tables are empty, we ensure a cleanup process took place
#   (since the test scenario comes with data). We know migrations are not just reverted,
#   the whole file is rather emptied. Therefor, we don’t need to test **all** tables.
table-empty() {
	local table_name="${1:?}"
	local row_count="$(sqlite3 "${DATABASE_PATH:?}" "SELECT CASE
  WHEN EXISTS (SELECT 1 FROM sqlite_master WHERE type='table' AND name='${table_name}')
  THEN (SELECT COUNT(*) FROM ${table_name})
  ELSE 0
END;" 2>&1)"
	if [[ "${row_count:?}" != "0" ]]; then
		if [[ "${row_count:?}" != *"no such table"* ]]; then
			die "API database table $(format_code "${table_name}") isn’t empty. It contains ${row_count:-NaN} row(s). Database path: $(format_url "${DATABASE_PATH:?}")."
		fi
	fi
}
table-empty member
table-empty pod_config
table-empty workspace_invitation
table-empty kv_store
success API database reset

if [ "$(cat "${PROSE_CONFIG_FILE:?}")" != "$(cat "${INTEGRATION_TESTS_DIR:?}"/prose-config-empty/prose.toml)" ]; then
	die "API config file wasn’t reset ($(format_url "${PROSE_CONFIG_FILE:?}") isn’t empty)."
fi
success API config file reset

info Initializing static config and reloading…
cat <<'EOF' > "${PROSE_CONFIG_FILE:?}"
[server]
domain = "test.local"

[notifiers.email]
smtp_host = "mailpit"
smtp_encrypt = false

EOF
edo xh POST -Iq "${INTEGRATION_TEST_HOST:?}"/reload || abort

info Waiting for the API to restart…
wait_until_api_running "${INTEGRATION_TEST_HOST:?}"

info Checking if the API still works…
# Run the `init` integration test, which will initialize the Pod
# (saving us a bunch of `curl`/`xh` commands).
( export SKIP_POD_START=1 SKIP_POD_STOP=1; edo log_as_trace_ task integration-test -- init )
success The API still works!

retry() {
	unset TOKEN CONFIRMATION

	TOKEN="$(xh POST -I "${INTEGRATION_TEST_HOST:?}"/v1/login \
		-a 'pauline.collins@test.local:demo' \
		content-type: \
		| jq -r '.token')"
	[ -n "${TOKEN-}" ] && [ "${TOKEN:?}" != null ] || abort

	CONFIRMATION="$(xh DELETE -I "${INTEGRATION_TEST_HOST:?}" \
		-A bearer -a "${TOKEN:?}" \
		password=demo \
		| jq -r '.confirmation')"
	[ -n "${CONFIRMATION-}" ] && [ "${CONFIRMATION:?}" != null ] || abort

	edo xh DELETE -Iq "${INTEGRATION_TEST_HOST:?}" \
		-A bearer -a "${TOKEN:?}" \
		confirmation="${CONFIRMATION:?}" || abort

	# Wait a bit to make sure the API is ready (e.g. has run migrations).
	sleep 1

	cat <<'EOF' > "${PROSE_CONFIG_FILE:?}"
[server]
domain = "test.local"

[notifiers.email]
smtp_host = "mailpit"
smtp_encrypt = false

EOF
	edo xh POST -Iq "${INTEGRATION_TEST_HOST:?}"/reload || abort

	wait_until_api_running "${INTEGRATION_TEST_HOST:?}"
	success It worked!
}

info 'Trying a second factory reset…'
wait_until_api_running "${INTEGRATION_TEST_HOST:?}"
# NOTE: This time we don’t need to initialize the Pod again as
#   `task integration-test -- init` did it already.
retry

info 'Trying a third factory reset (because why not?)…'
wait_until_api_running "${INTEGRATION_TEST_HOST:?}"
edo xh PUT -Iv "${INTEGRATION_TEST_HOST:?}"/v1/init/first-account \
	username=pauline.collins \
	password=demo \
	nickname=Whatever
retry

# Everything worked, no need to investigate.
# Delete the ephemeral scenario.
edo task local:stop
