#!/usr/bin/env bash

install_elixir() {
  local install_type=$1
  local version=$2
  local install_path=$3
  local tmp_download_dir

  if [ -n "$ASDF_DOWNLOAD_PATH" ]; then
    [ ! -d "$ASDF_DOWNLOAD_PATH" ] && mkdir -p "$ASDF_DOWNLOAD_PATH"
    tmp_download_dir="$ASDF_DOWNLOAD_PATH"
  elif [ -z "$TMPDIR" ]; then
    tmp_download_dir="$(mktemp -d -t elixir_build_XXXXXX)"
  else
    tmp_download_dir="$TMPDIR"
  fi

  if [ "$install_type" = "version" ]; then
    install_elixir_version "$version" "$install_path" "$tmp_download_dir"
  else
    install_elixir_ref "$version" "$install_path" "$tmp_download_dir"
  fi

  mkdir -p "$install_path/.mix/archives"
}

install_elixir_version() {
  local version=$1
  local install_path=$2
  local tmp_download_dir=$3

  # path to the tar file
  local source_path="$tmp_download_dir/elixir-precompiled-${version}.zip"
  download_zip_file_for_version "$version" "$source_path"

  echo "==> Copying release into place"

  if ! type "unzip" &>/dev/null; then
    echo "ERROR: Command 'unzip' not found."
    echo "unzip must be installed on your system."
    exit 1
  fi

  unzip -q "$source_path" -d "$install_path" || exit 1
}

install_elixir_ref() {
  local ref=$1
  local install_path=$2
  local tmp_download_dir=$3

  # path to the tar file
  local source_path="$tmp_download_dir/elixir-ref-${ref}-src.tar.gz"
  download_source_archive_for_ref "$ref" "$source_path"

  echo "==> Making the release"

  # Expand source archive
  tar zxf "$source_path" -C "$install_path" --strip-components=1 || exit 1

  # Build from source in a subshell because we don't want to disturb current working dir
  # installing using DESTDIR makes sure there are no tempfiles in the install dir
  # and fixes compatibility issues with the elixir-ls language server project
  if ! (
    cd "$install_path" || exit 1
    make clean test DESTDIR="$install_path" install
  ); then
    # handle the result
    echo "Build failed, cleaning..."
    rm -rf "$install_path"
    exit 1
  else
    echo "Build succeeded!"
    cp -a "$install_path/usr/local/." "$install_path/"
    rm -rf "${install_path:?}/usr"
  fi
}

download_zip_file_for_version() {
  local version=$1
  local download_path=$2
  local download_url
  download_url="$(get_download_url_for_version "$version")"

  # determine if the file exists
  echo "==> Checking whether specified Elixir release exists..."
  http_status=$(curl -I -w '%{http_code}' -s -o /dev/null "$download_url")

  if [ "$http_status" -eq 404 ] || [ "$http_status" -eq 403 ]; then
    cat <<EOS
==> Elixir version not found.

Hex.pm returned a ${http_status} for the following URL:

${download_url}

You can view a list of all Elixir releases by running 'asdf list-all elixir'.

Note: If you want to download a specific release of Elixir, please
specify the full version number (e.g. 1.2.1 instead of 1.3).
EOS

    exit 1 # non zero due to file not existing
  fi

  echo "==> Downloading ${version} to ${download_path}"
  curl -Lo "$download_path" -C - "$download_url"
}

download_source_archive_for_ref() {
  local ref=$1
  local download_path=$2
  local download_url="https://github.com/elixir-lang/elixir/archive/${ref}.tar.gz"

  # determine if the file exists
  echo "==> Checking whether specified Elixir reference exists..."
  http_status=$(curl -I -w '%{http_code}' -s -o /dev/null "$download_url")

  if [ "$http_status" -eq 404 ]; then
    cat <<EOS
==> Elixir reference not found.

GitHub returned a 404 for the following URL:

${download_url}

You can view a list of all Elixir releases by running 'asdf list-all elixir'
or by visiting https://github.com/elixir-lang/elixir/releases

Note: If you want to specify a git reference by which to install
Elixir, it must be a valid git tag or branch (generally of the form v1.2.1).
EOS

    exit 1 # non zero due to file not existing
  fi

  echo "==> Downloading ${ref} to ${download_path}"
  curl -Lo "$download_path" -C - "$download_url"
}

get_download_url_for_version() {
  local version=$1

  # if version is a release number, prepend v
  if [[ "$version" =~ ^[0-9]+\.* ]]; then
    version="v${version}"
  fi

  echo "https://repo.hex.pm/builds/elixir/${version}.zip"
}

run_default_mix_commands() {
  local install_path=$1
  local default_mix_commands="${HOME}/.default-mix-commands"

  if [ ! -f "$default_mix_commands" ]; then return; fi

  while read -ra command; do
    echo -e "\nRunning \033[33mmix ${command[*]} --force\033[39m... "
    # shellcheck source=bin/exec-env
    source "$(dirname "$0")/exec-env"
    PATH=$install_path/bin:$PATH MIX_EXS="" "$install_path"/bin/mix "${command[@]}" --force </dev/null
  done <"$default_mix_commands"
}

install_elixir "$ASDF_INSTALL_TYPE" "$ASDF_INSTALL_VERSION" "$ASDF_INSTALL_PATH"
run_default_mix_commands "$ASDF_INSTALL_PATH"
