#!/usr/bin/env bash
#
# Runs setup.
# Run bin/setup help for info.
#
set -e
# shellcheck disable=SC1091
source "bin/deps"

#—————————————————————————————————————————————————————————————————————————————————————————————————————————————
# Private Functions
#—————————————————————————————————————————————————————————————————————————————————————————————————————————————

__setup::actions() {
  local sep="${1}"
  printf "${bldylw}$(lib::array::join "${sep}" $(lib::util::functions-matching "setup::" | sed 's/ main//g'))${clr}"
}

#—————————————————————————————————————————————————————————————————————————————————————————————————————————————
# Public Functions
#—————————————————————————————————————————————————————————————————————————————————————————————————————————————

setup::help() {
  printf "
$(help-header USAGE)
  ${bldblk}# without any arguments runs a complete setup.${clr}
$(help-usage "bin/setup")

  ${bldblk}# alternatively, a sub-setup function name can be passed:${clr}
$(help-usage "bin/setup [ $(__setup::actions " | ") ]")

$(help-header DESCRIPTION:)
  Runs full setup without any arguments.

  Accepts one optional argument — one of the actions that typically run
  as part of setup, with one exception — ${bldylw}remove-git-hook${clr}.
  This action removes the git commit hook installed by the setup.

$(help-header EXAMPLES:)
$(help-example "bin/setup")

  Or, to run only one of the sub-functions (actions), pass
  it as an argument:

$(help-example bin/setup help)
$(help-example bin/setup remove-git-hook)

etc.
 "
}

setup::gems() {
  for gem in rubocop relaxed-rubocop rubocop-performance; do
    lib::gem::install ${gem}
  done
}

setup::remove-git-hook() {
  set -e
  [[ -L .git/hooks/pre-commit ]] && {
    info 'Removing git commit hook...'
    run "rm -f .git/hooks/pre-commit"
    echo
  }
  set +e
}

setup::git-hook() {
  set -e
  if [[ ! -L .git/hooks/pre-commit ]]; then
    info 'Installing git pre-commit hook'
    run "cd .git/hooks && ln -nfs ../../bin/linter pre-commit && cd -"
  else
    info: "git pre-commit hook is already installed."
  fi
  set +e
}

setup::os-specific() {
  local os=$(uname -s | tr '[:upper:]' '[:lower:]')
  local setup_script
  setup_script="./bin/setup-${os}"

  if [[ -x "${setup_script}" ]]; then
    set -e
    # shellcheck disable=SC1090
    source "${setup_script}"
    # run it's main function
    eval "setup::${os} \"$*\""
    echo
    if [[ -z ${CI} ]]; then
      h2 "Please note — to print your Bazel environment run " "${bldylw}bin/show-env"
    else
      /usr/bin/env bash bin/show-env || true
    fi
  else
    error "Operating system ${os} is not currently supported." >&2
  fi
  echo
  return 0
}

setup::main() {
  local action="$1"
  [[ "${action}" == "-h" || ${action} == "--help" ]] && action="help"
  local func="setup::${action}"

  if [[ -n ${action} ]]; then
    if lib::util::is-a-function "${func}"; then
      [[ ${action} != "help" ]] && h2 "Executing partial setup for action ${bldylw}${action}"
      shift
      ${func} "$@"
      local code=$?
      [[ ${code} -eq 0 ]] && success "Setup for ${action} was successful"
      [[ ${code} -ne 0 ]] && error "Error setting up ${action}"
      exit ${code}
    else
      h1 "Invalid action provided." "Valid actions are: $(__setup::actions " | ")"
      exit 1
    fi
  else
    set +e
    h2 "Installing required development dependencies for working with rules_ruby and Bazel."
    setup::gems
    [[ -z ${CI} ]] && setup::git-hook
    setup::os-specific "$@"
  fi
}

setup::main "$@"
