#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
ROOT="$(cd "$SCRIPT_DIR"/.. && pwd)"

# shellcheck source-path=SCRIPTDIR
source "$SCRIPT_DIR/style.sh"

TEST="$1"
TEST_SCRIPT="$SCRIPT_DIR/$TEST"

setup_isolated_env() {
  TEST_ISOLATED_DIR="$(mktemp --tmpdir --directory "$(basename "$TEST").XXXXXX")"
  if [[ $(os) == "macos" ]]; then
    TEST_ISOLATED_DIR="$(realpath "$TEST_ISOLATED_DIR")"
  fi

  # Use a fake HOME and a fake temporary directory
  TEST_HOME="$TEST_ISOLATED_DIR/home"
  TEST_WORKDIR="$TEST_HOME/workdir"
  TEST_TMPDIR="$TEST_ISOLATED_DIR/tmp"

  # Tell mise to look for its directory in the isolated environment
  MISE_SYSTEM_DIR="$TEST_ISOLATED_DIR/etc/mise"
  MISE_DATA_DIR="$TEST_HOME/.local/share/mise"
  MISE_CACHE_DIR="$TEST_HOME/.cache/mise"
  MISE_CONFIG_DIR="$TEST_HOME/.config/mise"
  MISE_STATE_DIR="$TEST_HOME/.local/state/mise"

  # Set default values
  : "${CARGO_HOME:=$HOME/.cargo}"
  : "${RUSTUP_HOME:=$HOME/.rustup}"
}

create_isolated_env() {
  # Create the required directories
  mkdir -p "$TEST_HOME/bin" "$TEST_WORKDIR" "$TEST_TMPDIR" "$MISE_SYSTEM_DIR" "$MISE_DATA_DIR" "$MISE_STATE_DIR" "$MISE_CACHE_DIR" "$MISE_CONFIG_DIR"

  # The dummy plugin is required for some tests
  mkdir -p "$MISE_DATA_DIR/plugins"
  ln -s "$ROOT/test/data/plugins/dummy" "$MISE_DATA_DIR/plugins/dummy"
}

remove_isolated_env() {
  rm -rf "$TEST_ISOLATED_DIR" &
}

within_isolated_env() {
  _env \
    --ignore-environment \
    --chdir="$TEST_WORKDIR" \
    - \
    CARGO_HOME="$CARGO_HOME" \
    CARGO_LLVM_COV="${CARGO_LLVM_COV:-}" \
    CARGO_LLVM_COV_SHOW_ENV="${CARGO_LLVM_COV_SHOW_ENV:-}" \
    CARGO_LLVM_COV_TARGET_DIR="${CARGO_LLVM_COV_TARGET_DIR:-}" \
    GITHUB_ACTION="${GITHUB_ACTION:-}" \
    GITHUB_API_TOKEN="${GITHUB_API_TOKEN:-}" \
    GOPROXY="${GOPROXY:-}" \
    HOME="$TEST_HOME" \
    LLVM_PROFILE_FILE="${LLVM_PROFILE_FILE:-}" \
    MISE_CACHE_DIR="$MISE_CACHE_DIR" \
    MISE_CONFIG_DIR="$MISE_CONFIG_DIR" \
    MISE_DATA_DIR="$MISE_DATA_DIR" \
    MISE_DEBUG="${MISE_DEBUG:-0}" \
    MISE_EXPERIMENTAL=1 \
    MISE_LOG_LEVEL="${MISE_LOG_LEVEL:-}" \
    MISE_STATE_DIR="$MISE_STATE_DIR" \
    MISE_SYSTEM_DIR="$MISE_SYSTEM_DIR" \
    MISE_TMP_DIR="$TEST_TMPDIR" \
    MISE_TRACE="${MISE_TRACE:-0}" \
    MISE_TRUSTED_CONFIG_PATHS="$TEST_ISOLATED_DIR" \
    MISE_YES=1 \
    PATH="${CARGO_TARGET_DIR:-$ROOT/target}/debug:$HOME/mise/bin:$CARGO_HOME/bin:$TEST_HOME/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin" \
    RUST_BACKTRACE="${RUST_BACKTRACE:-1}" \
    ROOT="$ROOT" \
    RUSTUP_HOME="$RUSTUP_HOME" \
    SHELL="$(type -p bash)" \
    TEST_DIR="$(dirname "$TEST_SCRIPT")" \
    TEST_NAME="$TEST" \
    TEST_ROOT="$SCRIPT_DIR" \
    TEST_SCRIPT="$TEST_SCRIPT" \
    TMPDIR="$TEST_TMPDIR" \
    "$@" || return $?
}

run_test() {
  setup_isolated_env
  create_isolated_env

  local status=0

  START="$(date +%s)"
  within_isolated_env bash --noprofile --norc -euo pipefail -c "source $SCRIPT_DIR/assert.sh && source $TEST_SCRIPT" || status=$?
  END="$(date +%s)"
  DURATION=$((END - START))s

  echo "$TEST: $DURATION" >&2

  if [[ "$status" == 0 ]]; then
    remove_isolated_env
    summary "$TEST" "$DURATION" ":white_check_mark:"
  else
    title="E2E test $TEST failed" err "exited with status code $status"
    echo "Test environment can be examined in $TEST_ISOLATED_DIR" >&2
    summary "$TEST" "$DURATION" ":x:"
  fi

  return "$status"
}

_env() {
  if type genv >/dev/null 2>&1; then
    genv "$@"
  else
    env "$@"
  fi
}

os() {
  case "$(uname -s)" in
    Darwin) echo "macos" ;;
    Linux) echo "linux" ;;
    *) echo "unknown" ;;
  esac
}

as_group "E2E $TEST" run_test
