#!/usr/bin/env bash
set -uo pipefail

# DO NOT set -e, otherwise error responses won't be shown to the user.

# bs_android uploads APKs for UI testing on BrowserStack. Upon successful
# completion, it returns build ID of the test run on BrowserStack.
#
# It forwards all arguments to "patrol build android", so you can pass --target,
# --flavor, --exclude etc. just as you would pass them to "patrol_cli".
#
# It can also be configured with the following environment variables:
BS_CREDENTIALS="${BS_CREDENTIALS:-}"
BS_PROJECT="${BS_PROJECT:-}"
BS_ANDROID_DEVICES="${BS_ANDROID_DEVICES:-}"
BS_SKIP_BUILD="${BS_SKIP_BUILD:-0}"
BS_IDLE_TIMEOUT="${BS_IDLE_TIMEOUT:-900}"

# Capture all arguments because they'll be consumed by getopt
original_args=("$@")

# Argument parsing start
FLAVOR=""
FLAVOR_SUFFIXED="-"
FLAVOR_DIR="/"

TEMP=$(getopt -n "$0" -a -l "flavor:" -- -- "$@")
eval set -- "$TEMP"
while [ $# -gt 0 ]; do
	case "$1" in
	--flavor)
		FLAVOR="$2"
		shift
		;;
	--) shift ;;
	esac
	shift
done

if [ -n "$FLAVOR" ]; then
	echo 1>&2 "Passed flavor: $FLAVOR"
	FLAVOR_SUFFIXED="-$FLAVOR-"
	FLAVOR_DIR="/$FLAVOR/"
fi
# Argument parsing end

if [ -z "$BS_CREDENTIALS" ]; then
	echo 1>&2 "Error: BS_CREDENTIALS not set"
	exit 1
fi

if [ -z "$BS_PROJECT" ]; then
	default_project="Unnamed Android project"
	echo 1>&2 "BS_PROJECT not set, using default: $default_project"
	BS_PROJECT="$default_project"
fi

if [ -z "$BS_ANDROID_DEVICES" ]; then
	default_devices="[\"Google Pixel 4-10.0\"]"
	echo 1>&2 "BS_ANDROID_DEVICES not set, using default: $default_devices"
	BS_ANDROID_DEVICES="$default_devices"
fi

if [ "$BS_SKIP_BUILD" = 1 ]; then
	echo 1>&2 "BS_SKIP_BUILD set to 1, build was skipped"
else
	patrol 1>&2 build android "${original_args[@]}"
fi

app_path="$PWD/build/app/outputs/apk${FLAVOR_DIR}debug/app${FLAVOR_SUFFIXED}debug.apk"
if [ ! -f "$app_path" ]; then
	echo 1>&2 "Error: apk not found at $app_path"
	exit 1
fi

# https://www.browserstack.com/docs/app-automate/api-reference/espresso/apps#upload-an-app
printf 1>&2 "Will upload app under test from %s\n\n" "$app_path"
if ! app_upload_response="$(
	curl --fail-with-body --user "$BS_CREDENTIALS" \
		--request POST "https://api-cloud.browserstack.com/app-automate/espresso/v2/app" \
		--form "file=@$app_path"
)"; then
	echo 1>&2 "Error: failed to upload app under test"
	echo 1>&2 "$app_upload_response"
	exit 1
fi

app_url="$(echo "$app_upload_response" | jq --raw-output .app_url)"
echo 1>&2 "Uploaded app under test, url: $app_url"

test_path="$PWD/build/app/outputs/apk/androidTest${FLAVOR_DIR}debug/app${FLAVOR_SUFFIXED}debug-androidTest.apk"
if [ ! -f "$test_path" ]; then
	echo 1>&2 "Error: test apk not found at $test_path"
	exit 1
fi

# https://www.browserstack.com/docs/app-automate/api-reference/espresso/tests#upload-a-test-suite
printf 1>&2 "Will upload test instrumentation app from %s\n\n" "$test_path"
if ! test_upload_response="$(
	curl --fail-with-body --user "$BS_CREDENTIALS" \
		--request POST "https://api-cloud.browserstack.com/app-automate/espresso/v2/test-suite" \
		--form "file=@$test_path"
)"; then
	echo 1>&2 "Error: failed to upload test instrumentation app"
	echo 1>&2 "$test_upload_response"
	exit 1
fi

test_url="$(echo "$test_upload_response" | jq --raw-output .test_suite_url)"
echo 1>&2 "Uploaded test instrumentation app, url: $test_url"

# https://www.browserstack.com/docs/app-automate/api-reference/espresso/builds#execute-a-build
printf 1>&2 "Will schedule test execution\n\n"
if ! run_response="$(
	curl --fail-with-body --user "$BS_CREDENTIALS" \
		--request POST "https://api-cloud.browserstack.com/app-automate/espresso/v2/build" \
		--header "Content-Type: application/json" \
		--data-binary @- <<EOF
{
    "app": "$app_url",
    "testSuite": "$test_url",
    "project": "$BS_PROJECT",
    "devices": $BS_ANDROID_DEVICES,
    "singleRunnerInvocation": "true",
    "useOrchestrator": "true",
    "clearPackageData": "true",
    "deviceLogs": "true",
    "local": "false",
    "idleTimeout": $BS_IDLE_TIMEOUT
}
EOF
)"; then
	echo 1>&2 "Error: failed to schedule test execution"
	echo 1>&2 "$run_response"
	exit 1
fi

printf 1>&2 "\n\nScheduled test execution\n"

build_id="$(echo "$run_response" | jq --raw-output .build_id)"
echo "$build_id"
