#!/usr/bin/env bash

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

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

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

source "$(dirname $0)"/constants.sh
PROSE_POD_API_IMAGE_TAG="${LOCAL_DOCKER_TAG:?}"
source "$(dirname $0)"/image-names.sh

# ===== HELPER FUNCTIONS =====

source "$(dirname $0)"/util.sh

description() {
	cat <<EOF
${Bold}Builds the Prose Pod API Docker image.${Bold_Off}

By default, the Docker image will be named $(format_code ${PROSE_POD_API_IMAGE:?}) but you can override
this by defining $(format_code PROSE_POD_API_IMAGE). This script also allows cross-compiling for a different
platform (see the list of supported platforms using $(format_code 'docker buildx ls')).
EOF
}

usage() {
	cat <<EOF
$(format_title 'Usage:')
  You want to build the Prose Pod API for a local usage:
    $(format_command "${SELF:?}") $(format_opt_arg --profile=dev)
  You want to build $(format_code "${PROSE_POD_API_IMAGE_NAME:?}:latest"):
    $(format_command "${SELF:?}") $(format_arg --tag=latest)
  You want to build the Prose Pod API for a different platform:
    $(format_command "${SELF:?}") $(format_arg --platform=TARGET_PLATFORM)

$(format_title 'Options:')
  $(format_subtitle 'Build phase options:')
    $(format_flag --platform=TARGET_PLATFORM)
      A platform to cross-compile for.
      $(format_secondary "See the list of supported targets via $(format_code 'docker buildx ls').")
    $(format_flag --tag=DOCKER_TAG)
      Choose which version of the Prose Pod API to build (default: "${PROSE_POD_API_IMAGE_TAG:?}").
    $(format_flag --profile=CARGO_PROFILE)
      Choose which Cargo profile to use when building the Prose Pod API.
      $(format_secondary "Note: $(format_code '--profile=dev') enables $(format_code 'debug_only') configuration.")
    $(format_flag --locked)
      Build with locked versions (specified in $(format_code 'Cargo.lock')).
      $(format_secondary "Ensures no dependency gets silently updated and breaks builds.")
    $(format_flag --no-pull)
      Do not pull referenced Docker images.
      $(format_secondary "Speeds up the builds and does not use the network, but does not update base images.")
    $(format_flag --offline)
      Build without accessing the network (implies $(format_flag --no-pull)).

  $(format_subtitle 'Miscellaneous options:')
    $(format_flag --help)
      Explains what the command does and how to use it.
    $(format_flag --dry-run)
      Do a dry run (i.e. print what would be executed instead of running it).
    $(format_flag --debug)
      Log debug messages when running the script.
    $(format_flag --trace)
      Log tracing messages when running the script.
EOF
	# NOTE: Outdated documentation, kept for when we'll reintroduce this flag.
	# $(format_flag --offline)
	#   Run without accessing the network. Implies $(format_flag --no-pull).
	#   $(format_secondary "Speeds up the builds and does not use the network, but does not update crates.")
}

help() {
	printf "$(description)\n"
	echo ''
	printf "$(usage)\n"
	exit 0
}

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

CARGO_INSTALL_EXTRA_ARGS=()
CARGO_PROFILE=release
unset NO_PULL

for arg in "$@"; do
	case $arg in
		--platform=*)
			change-build-target "${arg#'--platform='}"
			;;
		--tag=*)
			PROSE_POD_API_IMAGE_TAG="${arg#'--tag='}"
			;;
		--profile=*)
			CARGO_PROFILE="${arg#'--profile='}"
			;;
		--offline)
			info 'Will build without accesing the network.'
			CARGO_INSTALL_EXTRA_ARGS+=('--offline')
			info 'Will not pull referenced Docker images.'
			NO_PULL=1
			;;
		--locked)
			info 'Will build with locked versions.'
			CARGO_INSTALL_EXTRA_ARGS+=('--locked')
			;;
		--no-pull)
			info 'Will not pull referenced Docker images.'
			NO_PULL=1
			;;
		--help) help ;;
		--dry-run) export DRY_RUN=1 ;;
		--debug) export LOG_DEBUG=1 ;;
		--trace) export LOG_TRACE=1 ;;
		*) error "Unknown argument: $(format_code $arg)."; info "$(usage)"; die ;;
	esac
done

# Recompute log levels.
source "${BASH_TOOLBOX:?}"/log.sh

info "Will build with profile $(format_code "${CARGO_PROFILE:?}")."

# Regenerate image name.
unset PROSE_POD_API_IMAGE
source "${SCRIPTS_ROOT:?}"/image-names.sh

if [ -z "${TARGET_PLATFORM}" ]; then
	info "Will build $(format_code $PROSE_POD_API_IMAGE) for the local platform."
else
	info "Will build $(format_code $PROSE_POD_API_IMAGE) for the $(format_code $TARGET_PLATFORM) platform."
fi

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

if [ -z "$(git status -s)" ]; then
	COMMIT="$(git rev-parse HEAD)"
else
	warn 'You have uncommitted changes, the API version will have no commit hash information.'
fi

edo docker buildx build \
	${DOCKER_TARGET_PLATFORM:+--platform "${DOCKER_TARGET_PLATFORM:?}"} \
	-t "${PROSE_POD_API_IMAGE:?}" \
	${CARGO_PROFILE:+--build-arg CARGO_PROFILE="${CARGO_PROFILE}"} \
	${CARGO_INSTALL_EXTRA_ARGS:+--build-arg CARGO_INSTALL_EXTRA_ARGS="${CARGO_INSTALL_EXTRA_ARGS[*]}"} \
	--build-arg VERSION="${PROSE_POD_API_IMAGE_TAG:?}" \
	--build-arg COMMIT="${COMMIT:-}" \
	${NO_PULL:+--pull=false} \
	${DOCKERFILE_PATH:+-f "${DOCKERFILE_PATH:?}"} \
	"${PROSE_POD_API_DIR:?}"
