#!/usr/bin/env bash

# Whenever Bazel is invoked, it first calls this script setting "BAZEL_REAL" to the path of the real Bazel binary.
# Use this file as a wrapper for any logic that should run before bazel itself is executed.

# WARNING : If you run //:compiledb target, you can not print to stdout in this file as it will fail with
# "Bazel aquery failed." because it is reading this files stdout as aquery output

REPO_ROOT=$(dirname $(dirname $(realpath "$0")))
bazel_real="$BAZEL_REAL"



# If disk space becomes an issue, this block can be used to clean up configs
# when disk space is getting low. It is commented out because "bazel info output_path"
# takes .5 seconds, and no need to add that extra time unless disk space becomes a large
# problem

#if [ $# -eq 2 ] || [ $# -eq 3 ]; then
#    if [ "$1" = "build" ]; then
#        output_path=$($bazel_real info output_path)
#        remaining_kb=$(df --output=avail $output_path | tail -n 1)
#        remaining_gb=$(($remaining_kb / 1024 / 1024))
#        fastbuild_dir=${output_path}/aarch64-fastbuild
#        dbg_dir=${output_path}/aarch64-dbg
#        opt_dir=${output_path}/aarch64-opt
#        if [ "$remaining_gb" -lt 40 ]; then
#          echo "Disk space is getting low (under 40GB) - cleaning up other config outputs"
#          if [ $# -eq 2 ]; then
#            rm -rf "$dbg_dir" &>/dev/null
#            rm -rf "$opt_dir" &>/dev/null
#          elif [[ "$2" == "--config=fastbuild"* ]]; then
#            rm -rf "$dbg_dir" &>/dev/null
#            rm -rf "$opt_dir" &>/dev/null
#          elif [[ "$2" == "--config=dbg"* ]]; then
#            rm -rf "$fastbuild_dir" &>/dev/null
#            rm -rf "$opt_dir" &>/dev/null
#          elif [[ "$2" == "--config=opt"* ]]; then
#            rm -rf "$fastbuild_dir" &>/dev/null
#            rm -rf "$dbg_dir" &>/dev/null
#          fi
#        fi
#    fi
#fi

if [[ -z "${BAZELISK_SKIP_WRAPPER}" ]]; then
    echo "You're not using Bazelisk, which is recommended for a consistent build environment." >&2
    echo "Your version of Bazel may be mismatched with the version intended to be used to build MongoDB." >&2
    echo "Please run the following command to install Bazelisk and make sure to add ~/.local/bin to your PATH:" >&2
    echo "" >&2
    echo "python buildscripts/install_bazel.py" >&2
    exit 0
fi

echo "common --//bazel/config:running_through_bazelisk" > $REPO_ROOT/.bazelrc.bazelisk

if [[ $MONGO_BAZEL_WRAPPER_DEBUG == 1 ]]; then
    wrapper_start_time="$(date -u +%s.%N)"
fi
 
# detect os and arch so we can try to find python later
if [[ "$OSTYPE" == "linux"* ]]; then
  os="linux"
elif [[ "$OSTYPE" == "darwin"* ]]; then
  os="macos"
else
  os="unknown"
fi

ARCH=$(uname -m)
if [[ "$ARCH" == "arm64" || "$ARCH" == "aarch64" ]]; then
  ARCH="arm64"
elif [[ "$ARCH" == "ppc64le" || "$ARCH" == "ppc64" || "$ARCH" == "ppc" || "$ARCH" == "ppcle" ]]; then
  ARCH="ppc64le"
elif [[ "$ARCH" == "s390x" || "$ARCH" == "s390" ]]; then
  ARCH="s390x"
else
  ARCH="x86_64"
fi

# setup usual locations to look for certs for python to use
declare -a cert_locs=()
cert_locs+=("/etc/ssl/certs/ca-certificates.crt")                # Debian/Ubuntu/Gentoo etc.
cert_locs+=("/etc/pki/tls/certs/ca-bundle.crt")                  # Fedora/RHEL 6
cert_locs+=("/etc/ssl/ca-bundle.pem")                            # OpenSUSE
cert_locs+=("/etc/pki/tls/cacert.pem")                           # OpenELEC
cert_locs+=("/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem") # CentOS/RHEL 7
cert_locs+=("/etc/ssl/cert.pem")                                 # Alpine Linux

for cert in ${cert_locs[@]}; do
  if [ -f $cert ]; then
    export SSL_CERT_DIR=$(dirname $cert)
    export SSL_CERT_FILE=$cert
    break
  fi
done

# skip python if the bazel command type is in a known list of commands to skip
skip_python=0
bazel_commands=()
while IFS= read -r line; do
  bazel_commands+=("$line")
done < $REPO_ROOT/bazel/wrapper_hook/bazel_commands.commands

current_bazel_command=""
for arg do
  for command in "${bazel_commands[@]}"
  do
    if [ "$command" == "$arg" ] ; then
      current_bazel_command="$arg"
      break
    fi
  done
  if [ ! -z $current_bazel_command ]; then
    break
  fi
done

if [ -z $current_bazel_command ]; then
  skip_python=1
fi

if [ "$skip_python" == "0" ]; then
  # known list of commands to skip
  skip_commands=("clean" "version" "shutdown" "info")

  for command in "${skip_commands[@]}"
  do
    if [ "$current_bazel_command" == "$command" ] ; then
      skip_python=1
      break
    fi
  done
fi

if [ "$skip_python" == "1" ]; then
  exec "$bazel_real" $@
fi

# find existing python installs
cur_dir=$(basename $REPO_ROOT)
python=""
standard_python_loc="$(readlink "$REPO_ROOT/bazel-$cur_dir")/../../external/_main~setup_mongo_python_toolchains~py_${os}_${ARCH}/dist/bin/python3"
if [ -d $REPO_ROOT/bazel-$cur_dir ]; then
  python="$(readlink "$REPO_ROOT/bazel-$cur_dir")/../../external/_main~setup_mongo_python_toolchains~py_${os}_${ARCH}/dist/bin/python3"
else
  if [ -d $REPO_ROOT/.compiledb/compiledb-$cur_dir ]; then
    python="$(readlink "$REPO_ROOT/.compiledb/compiledb-$cur_dir")/../../external/_main~setup_mongo_python_toolchains~py_${os}_${ARCH}/dist/bin/python3"
  fi
fi

# if no python use bazel to install one
if [[ "$python" = "" ]] || [ ! -f $python ]; then
  >&2 echo "python prereq missing, using bazel to install python..."
  >&2 $bazel_real build --bes_backend= --bes_results_url= @py_${os}_${ARCH}//:all
  if [[ $? != 0 ]]; then
    if [[ ! -z "$CI" ]] || [[ $MONGO_BAZEL_WRAPPER_FALLBACK == 1 ]]; then
      >&2 echo "wrapper script failed to install python! falling back to normal bazel call..."
      exec "$bazel_real" $@
    else
      exit $?
    fi
  fi
fi

# update python location if it was missing and we had to install it
if [[ "$python" = "" ]] || [ ! -f $python ]; then
  python="$(readlink "$REPO_ROOT/bazel-$cur_dir")/../../external/_main~setup_mongo_python_toolchains~py_${os}_${ARCH}/dist/bin/python3"
fi

autocomplete_query=0
# bash autocomplete detection
if [[ $* =~ ^.*--output_base=/tmp/.*-completion-$USER.*$ ]]; then
  autocomplete_query=1
fi
# zsh autocomplete detection
if [[ $* == *"--noblock_for_lock query kind(\".*_test\", //:all)"* ]] || [[ $* == *"--noblock_for_lock query kind(\".*_test\", :all)"* ]]; then
  autocomplete_query=1
fi

rm -f /tmp/mongo_autocomplete_plus_targets
MONGO_BAZEL_WRAPPER_ARGS=$(mktemp)

MONGO_BAZEL_WRAPPER_ARGS=$MONGO_BAZEL_WRAPPER_ARGS \
MONGO_AUTOCOMPLETE_QUERY=$autocomplete_query \
>&2 $python $REPO_ROOT/bazel/wrapper_hook/wrapper_hook.py $bazel_real "$@"
exit_code=$?
if [[ $exit_code != 0 ]]; then
  if [[ ! -z "$CI" ]] || [[ $MONGO_BAZEL_WRAPPER_FALLBACK == 1 ]]; then
    >&2 echo "wrapper script failed! falling back to normal bazel call..."
    exec "$bazel_real" $@
  else
    exit $? 
  fi
fi

new_args=()
while IFS= read -r line; do
  new_args+=("$line")
done < $MONGO_BAZEL_WRAPPER_ARGS

if [[ $MONGO_BAZEL_WRAPPER_DEBUG == 1 ]] && [[ $autocomplete_query == 0 ]]; then
  wrapper_end_time="$(date -u +%s.%N)"
  runtime=$(bc <<< "$wrapper_end_time - $wrapper_start_time")
  runtime=$(printf "%0.3f" $runtime)
  >&2 echo "[WRAPPER_HOOK_DEBUG]: wrapper hook script input args: $@"
  >&2 echo "[WRAPPER_HOOK_DEBUG]: wrapper hook script new args: ${new_args[@]@Q}"
  >&2 echo "[WRAPPER_HOOK_DEBUG]: wrapper hook script took $runtime seconds"
fi

if [[ $autocomplete_query == 1 ]]; then
  plus_targets=$(</tmp/mongo_autocomplete_plus_targets)
  query_output=$("${new_args[@]@Q}") 
  echo $query_output $plus_targets | tr " " "\n"
else
  $bazel_real "${new_args[@]}"
  bazel_exit_code=$?
  # Run post-bazel hook in subshell
  (>&2 $python $REPO_ROOT/bazel/wrapper_hook/post_bazel_hook.py $bazel_real)
  exit $bazel_exit_code
fi
