#!/usr/bin/env bash

set -o pipefail
if [[ "${ASDF_DEBUG}" == "1" ]]; then
  set -x
fi

# shellcheck source=lib/utils.bash
. "$(dirname "$(dirname "$0")")/lib/utils.bash"

find_cmd() {
  local cmd_dir="$1"
  shift

  local cmd_name
  local args_offset="$#"
  cmd_name="command-$(tr ' ' '-' <<<"${@:1:${args_offset}}").bash"
  while [ ! -f "$cmd_dir/$cmd_name" ] && [ "$args_offset" -gt 0 ]; do
    args_offset=$((args_offset - 1))
    cmd_name="command-$(tr ' ' '-' <<<"${@:1:${args_offset}}").bash"
  done

  if [ -f "$cmd_dir/$cmd_name" ]; then
    printf "%s %s\n" "$cmd_dir/$cmd_name" "$((args_offset + 1))"
  elif [ -f "$cmd_dir/command.bash" ]; then
    printf "%s %s\n" "$cmd_dir/command.bash" 1
  fi
}

find_asdf_cmd() {
  local asdf_cmd_dir
  asdf_cmd_dir="$(asdf_dir)/lib/commands"
  case "$1" in
  'exec' | 'current' | 'env' | 'global' | 'install' | 'latest' | 'local' | \
    'reshim' | 'uninstall' | 'update' | 'where' | 'which' | \
    'export-shell-version')
    printf "%s %s\n" "$asdf_cmd_dir/command-$1.bash" 2
    ;;

  '' | '--help' | '-h' | 'help')
    printf "%s %s\n" "$asdf_cmd_dir/command-help.bash" 2
    ;;

  '--version' | 'version')
    printf "%s %s\n" "$asdf_cmd_dir/command-version.bash" 2
    ;;

  *)
    find_cmd "$asdf_cmd_dir" "$@"
    ;;
  esac
}

find_plugin_cmd() {
  local ASDF_CMD_FILE args_offset
  local result=
  result="$(find_cmd "$(get_plugin_path "$1")/lib/commands" "${@:2}")"
  ASDF_CMD_FILE=${result% *}
  args_offset=${result##* }
  if [ -n "$ASDF_CMD_FILE" ]; then
    args_offset=$((args_offset + 1)) # since the first argument is the plugin name
    printf "%s %s\n" "$ASDF_CMD_FILE" "$args_offset"
  fi
}

asdf_cmd() {
  local ASDF_CMD_FILE args_offset

  if [ "shell" = "$1" ]; then
    printf "Shell integration is not enabled. Please ensure you source asdf in your shell setup." >&2
    exit 1
  fi

  # Internal Variables
  ASDF_DEFAULT_TOOL_VERSIONS_FILENAME=$(asdf_tool_versions_filename)
  export ASDF_DEFAULT_TOOL_VERSIONS_FILENAME

  ASDF_CONFIG_FILE=$(asdf_config_file)
  export ASDF_CONFIG_FILE

  ASDF_DATA_DIR=$(asdf_data_dir)
  export ASDF_DATA_DIR

  ASDF_DIR=$(asdf_dir)
  export ASDF_DIR

  local result=
  result="$(find_asdf_cmd "$@")"
  ASDF_CMD_FILE=${result% *}
  args_offset=${result##* }
  if [ -z "$ASDF_CMD_FILE" ]; then
    result="$(find_plugin_cmd "$@")"
    ASDF_CMD_FILE=${result% *}
    args_offset=${result##* }
  fi

  if [ -x "$ASDF_CMD_FILE" ]; then
    # When '$ASDF_CMD_FILE' is an executable, we are executing a command directly from a plugin.
    # Example: https://github.com/asdf-community/asdf-nim/blob/397c14a7f04ad5b91963814afc2e9cc92366e1c5/lib/commands/command-install-deps.bash
    # In those cases, the path to that command is always an absolute path. However, this codepath can also be activated if a user accidentally
    # marks files in ./lib/commands/* as executable. This code detects when that happens and prints a useful warning message.
    if [[ "$ASDF_CMD_FILE" == ./lib/commands/* ]]; then
      printf '%s\n' "----------"
      printf '%s\n' "asdf: Warning: You are executing an asdf command from \$ASDF_DIR, but we detected that some files have been"
      printf '%s\n' "               erroneously marked as executable. All files under '$ASDF_DIR/lib/commands' must NOT be marked"
      printf '%s\n' "               as executable. Otherwise, asdf will not be able to source its core files"
      printf '%s\n' "----------"
    fi >&2

    exec "$ASDF_CMD_FILE" "${@:${args_offset}}"
  elif [ -f "$ASDF_CMD_FILE" ]; then
    set -- "${@:${args_offset}}"
    # shellcheck source=/dev/null
    . "$ASDF_CMD_FILE"
  else
    local asdf_cmd_dir
    asdf_cmd_dir="$(asdf_dir)/lib/commands"
    printf "%s\n" "Unknown command: \`asdf ${*}\`" >&2
    # shellcheck source=lib/commands/command-help.bash
    . "$asdf_cmd_dir/command-help.bash" >&2
    return 127
  fi
}

asdf_cmd "$@"
