#!/bin/sh
# shellcheck disable=SC2034,SC3043
set -eu

define_some_colors() {
  # Default: no colors. This must never break the installer.
  BG_RED=""; BG_GREEN=""; BG_YELLOW=""; BG_BLUE=""; BG_MAGENTA=""; BG_CYAN=""
  RED=""; GREEN=""; YELLOW=""; BLUE=""; MAGENTA=""; CYAN=""
  CLEAR=""

  # Only try tput if:
  # - stdout is a real terminal
  # - tput exists
  # - TERM is set
  if [ -t 1 ] && command -v tput >/dev/null 2>&1 && [ -n "${TERM:-}" ]; then
    BG_RED=$(tput setab 1 2>/dev/null || true)
    BG_GREEN=$(tput setab 2 2>/dev/null || true)
    BG_YELLOW=$(tput setab 3 2>/dev/null || true)
    BG_BLUE=$(tput setab 4 2>/dev/null || true)
    BG_MAGENTA=$(tput setab 5 2>/dev/null || true)
    BG_CYAN=$(tput setab 6 2>/dev/null || true)

    RED=$(tput setaf 1 2>/dev/null || true)
    GREEN=$(tput setaf 2 2>/dev/null || true)
    YELLOW=$(tput setaf 3 2>/dev/null || true)
    BLUE=$(tput setaf 4 2>/dev/null || true)
    MAGENTA=$(tput setaf 5 2>/dev/null || true)
    CYAN=$(tput setaf 6 2>/dev/null || true)

    CLEAR=$(tput sgr0 2>/dev/null || true)
  fi
}

detect_root() {
  if [ "$(id -u)" -ne "0" ]; then
    export I_AM_GROOT=False
    echo "${YELLOW}This script requires elevated privileges to install Border0 CLI, so you might get prompted for password.${CLEAR}"
  else
    export I_AM_GROOT=True
  fi
}

detect_os() {
  [ $DEBUG = true ] && printf "%sDetecting the OS...%s " "${BLUE}" "${CLEAR}"
  case "$(uname | tr '[:upper:]' '[:lower:]')" in
    darwin*)
      [ $DEBUG = true ] && echo "${GREEN}we are running on macOS${CLEAR}"
      export MY_OS="darwin"
      ;;
    linux*)
      [ $DEBUG = true ] && echo "${GREEN}we are running on Linux${CLEAR}"
      export MY_OS="linux"
      ;;
    cygwin*)
      [ $DEBUG = true ] && echo "${GREEN}we are running on Windows${CLEAR}"
      export MY_OS="windows"
      ;;
    msys*)
      [ $DEBUG = true ] && echo "${GREEN}we are running on Windows${CLEAR}"
      export MY_OS="windows"
      ;;
    *)
      echo "${RED}unknown: $(uname)${CLEAR}"
      export MY_OS="unknown"
      exit 1
      ;;
  esac
}

detect_arch() {
  [ $DEBUG = true ] && printf "%sDetecting machine OS arch...%s " "${BLUE}" "${CLEAR}"
  HW_MACHINE=$(uname -m)
  if [ -z "${HW_MACHINE##*x86_64*}" ]; then
    export MY_ARCH="amd64"
    if [ $DEBUG = true ]; then
      echo "${GREEN}our architecture is amd64${CLEAR}"
    fi
  elif [ -z "${HW_MACHINE##*aarch64*}" ]; then
    export MY_ARCH="arm64"
    if [ $DEBUG = true ]; then
      echo "${GREEN}our architecture is arm64${CLEAR}"
    fi
  elif [ -z "${HW_MACHINE##*arm64*}" ]; then
    export MY_ARCH="arm64"
    if [ $DEBUG = true ]; then
      echo "${GREEN}our architecture is arm64${CLEAR}"
    fi
  elif [ -z "${HW_MACHINE##*armv7l*}" ]; then
    export MY_ARCH="arm"
    if [ $DEBUG = true ]; then
      echo "${GREEN}our architecture is arm${CLEAR}"
    fi
  elif [ -z "${HW_MACHINE##*armv6l*}" ]; then
    export MY_ARCH="armv6"
    if [ $DEBUG = true ]; then
      echo "${GREEN}our architecture is armv6${CLEAR}"
    fi
  else
    echo "${YELLOW}could not determine architecture, using 64Bit${CLEAR}"
    export MY_ARCH="amd64"
  fi
}

generate_download_url() {
  DOWNLOAD_URL="https://download.border0.com/${MY_OS}_${MY_ARCH}/border0"
  if [ $DEBUG = true ]; then
    echo "${BLUE}Our download URL:${CLEAR} ${GREEN}${DOWNLOAD_URL}${CLEAR}"
  fi
}

detect_download_cmd() {
  DOWNLOAD_CMD=""

  [ $DEBUG = true ] && printf "%sChecking if cURL is available...%s " "${BLUE}" "${CLEAR}"
  hash curl 2> /dev/null && {
    export DOWNLOAD_CMD="curl"
    if [ $DEBUG = true ]; then
      echo "${GREEN}found cURL${CLEAR}"
    fi
    return
  }

  [ $DEBUG = true ] && printf "%sChecking if wget is available...%s " "${BLUE}" "${CLEAR}"
  hash wget 2> /dev/null && {
    export DOWNLOAD_CMD="wget"
    if [ $DEBUG = true ]; then
      echo "${GREEN}found wget${CLEAR}"
    fi
    return
  }

  if [ "$DOWNLOAD_CMD" = "" ]; then
    echo "${YELLOW}nope, no cURL or wget available${CLEAR}"
    echo "${RED}We have no way of downloading Border0 CLI, please install cURL or wget${CLEAR}"
    exit 1
  fi
}

download_border0_cli() {
  export BORDER0_TEMP_PATH="/tmp/border0.bin"
  if [ "$DOWNLOAD_CMD" = "curl" ]; then
    [ $DEBUG = true ] && echo "${BLUE}Fetching Border0 CLI tool from:${CLEAR} ${GREEN}${DOWNLOAD_URL} with cURL${CLEAR}"
    curl -s -o ${BORDER0_TEMP_PATH} ${DOWNLOAD_URL}
  elif [ "$DOWNLOAD_CMD" = "wget" ]; then
    [ $DEBUG = true ] && echo "${BLUE}Fetching Border0 CLI tool from:${CLEAR} ${GREEN}${DOWNLOAD_URL} with wget${CLEAR}"
    wget -q -O ${BORDER0_TEMP_PATH} ${DOWNLOAD_URL}
  fi
  chmod +x ${BORDER0_TEMP_PATH}
}

detect_sudo() {
  EXEC_ELEVATION_CMD=""
  [ $DEBUG = true ] && printf "%sChecking for sudo command...%s " "${BLUE}" "${CLEAR}"
  hash sudo 2> /dev/null && {
    export EXEC_ELEVATION_CMD="sudo"
    if [ $DEBUG = true ]; then
      echo "${GREEN}found sudo${CLEAR}"
    fi
    return
  }
  if [ "$EXEC_ELEVATION_CMD" = "" ]; then
    [ $DEBUG = true ] && printf "%ssudo is unavailable%s" "${YELLOW}" "${CLEAR}"
    export EXEC_ELEVATION_CMD="su"
    [ $DEBUG = true ] && echo " ${CYAN}...will try using su instead${CLEAR}"
  fi
}

install_border0_cli() {
  [ $DEBUG = true ] && printf "%sSelecting the install path:%s " "${BLUE}" "${CLEAR}"
  if [ -z "${PATH##*/usr/local/bin*}" ]; then
    export INSTALL_PATH="/usr/local/bin"
    [ $DEBUG = true ] && echo "${GREEN}${INSTALL_PATH} has been selected${CLEAR}"
  elif [ -z "${PATH##*/usr/local/sbin*}" ]; then
    export INSTALL_PATH="/usr/local/sbin"
    [ $DEBUG = true ] && echo "${GREEN}${INSTALL_PATH} has been selected${CLEAR}"
  elif [ -z "${PATH##*/usr/bin*}" ]; then
    export INSTALL_PATH="/usr/bin"
    [ $DEBUG = true ] && echo "${GREEN}${INSTALL_PATH} has been selected${CLEAR}"
  else
    export INSTALL_PATH="/bin"
    [ $DEBUG = true ] && echo "${GREEN}${INSTALL_PATH} has been selected${CLEAR}"
  fi

  export BORDER0_INSTALL_PATH="${INSTALL_PATH}/border0"
  export MOVE_CMD="mv -v ${BORDER0_TEMP_PATH} ${BORDER0_INSTALL_PATH}"
  if [ $I_AM_GROOT = True ]; then
    $MOVE_CMD
    [ $DEBUG = true ] && echo "${BLUE}Installing Border0 CLI tool in ${INSTALL_PATH}${CLEAR}"
  else
    [ $DEBUG = true ] && printf "%sChecking if we have access to the install path...%s " "${BLUE}" "${CLEAR}"
    if [ -w $INSTALL_PATH ]; then
      [ $DEBUG = true ] && echo "${GREEN}looks like we can write to ${INSTALL_PATH}${CLEAR}"
      $MOVE_CMD
      [ $DEBUG = true ] && echo "${BLUE}Installed Border0 CLI tool in ${INSTALL_PATH}${CLEAR}"
    else
      echo "${YELLOW}we can not write to ${INSTALL_PATH}${CLEAR}"
      detect_sudo
      if [ $EXEC_ELEVATION_CMD = "sudo" ]; then
        if [ ! -d $INSTALL_PATH ]; then
          [ $DEBUG = true ] && echo "${BLUE}Creating directory ${INSTALL_PATH}${CLEAR}"
          if ! sudo mkdir -p $INSTALL_PATH; then exit 1; fi
        fi
        # shellcheck disable=SC2086
        if ! sudo $MOVE_CMD; then exit 1; fi
      elif [ $EXEC_ELEVATION_CMD = "su" ]; then
        printf "Please provide root "
        if [ ! -d $INSTALL_PATH ]; then
          [ $DEBUG = true ] && echo "${BLUE}Creating directory ${INSTALL_PATH}${CLEAR}"
          if ! su -l root bash -c "mkdir -p $INSTALL_PATH"; then exit 1; fi
        fi
        if ! su -l root bash -c "$MOVE_CMD"; then exit 1; fi
      fi
    fi
  fi

  printf "%s" "${BLUE}"
  if [ ! -f $BORDER0_INSTALL_PATH ] || ! border0 --version > /dev/null 2>&1; then
    echo "${CLEAR}${BG_RED}⛔️ Something went wrong...${CLEAR}"
    echo "${YELLOW}Please reach out https://docs.border0.com/docs/getting-help, we'd love to learn about your experience${CLEAR}"
    exit 1
  fi

  echo "${CLEAR}${GREEN}🚀 Successfully installed Border0 CLI tool${CLEAR}"
}

parse_arguments() {
  INVITE_CODE=""
  CONNECTOR_NAME=""
  AWS=false
  DEBUG=false

  while [ "$#" -gt 0 ]; do
    case $1 in
      -i|--invite) INVITE_CODE="$2"; shift ;;
      -n|--name) CONNECTOR_NAME="$2"; shift ;;
      -a|--aws) AWS=true ;;
      -d|--debug) DEBUG=true ;;
      *) echo "Unknown argument passed: $1"; exit 1 ;;
    esac
    shift
  done
}

invite_to_connector_token() {
  [ $DEBUG = true ] && print_in_box "Exchange Border0 invite for connector token" "$BG_BLUE"

  local name payload response
  name="${CONNECTOR_NAME:-$(hostname)}"
  name="$(printf '%s' "$name" | tr '.' '-')" # replace dots with dashes
  payload='{"name":"'"${name}"'","install_token":"'"${INVITE_CODE}"'","built_in_ssh_service_enabled":true}'
  response="$(request_api '/connector/create_with_token' "$payload")"

  # extract "token" and "connector_id" from the response json
  BORDER0_TOKEN=$(echo "$response" | grep -o '"token":"[^"]*' | cut -d'"' -f4)
  CONNECTOR_ID=$(echo "$response" | grep -o '"connector_id":"[^"]*' | cut -d'"' -f4)

  echo "${CLEAR}${GREEN}👍 Connector token acquired${CLEAR}"
}

request_api() {
  local api endpoint url payload
  api="${BORDER0_API:-https://api.border0.com/api/v1}"
  endpoint="$1"
  payload="${2:-}"
  url="${api}${endpoint}"

  if [ "$DOWNLOAD_CMD" = "curl" ]; then
    curl -fsSL -XPOST -H "Content-Type: application/json" -d "$payload" "$url"
  elif [ "$DOWNLOAD_CMD" = "wget" ]; then
    wget -q -O- --header="Content-Type: application/json" --post-data="$payload" "$url"
  fi
}

install_border0_connector() {
  local portal link output
  portal="${BORDER0_WEB_URL:-https://portal.border0.com}"
  link="${portal}/connector/${CONNECTOR_ID}?show_message=new_connector_started"

  output=$(border0 connector status 2>&1)
  if echo "$output" | grep -q 'service is currently running'; then
    echo
    echo "🚀 ${BG_BLUE}Border0 connector service is already running.${CLEAR}"
    echo
    echo "${GREEN}👉 Click the link below to see your new connector:${CLEAR}"
    echo "${GREEN}👉 ${link}${CLEAR}"
    return
  fi

  if [ "$MY_OS" = "linux" ]; then
    # check if systemd is available only on Linux
    if command -v systemctl >/dev/null 2>&1; then
      if ! install_border0_connector_as_superuser; then
        echo
        start_border0_connector
      fi
    else
      start_border0_connector
    fi
  else
    # for everything else, just try to install the connector as superuser or fallback to running in the foreground
    if ! install_border0_connector_as_superuser; then
      echo
      start_border0_connector
    fi
  fi

  echo
  echo "🚀 🎉 🙌 🥳 ${BG_BLUE}Congrats! Successfully installed Border0 connector service.${CLEAR}"
  echo
  echo "${GREEN}👉 Click the link below to see your new connector:${CLEAR}"
  echo "${GREEN}👉 ${link}${CLEAR}"
}

start_border0_connector() {
  if [ $DEBUG = true ]; then
    print_in_box "Start Border0 Connector" "$BG_BLUE"
    echo "${GREEN}Executing>> BORDER0_TOKEN=<border0_token> border0 connector start${CLEAR}"
  fi
  echo
  echo "🚀 ${BG_BLUE}Border0 connector is running in the foreground.${CLEAR}"
  echo
  echo "${GREEN}👉 Click the link below to see your new connector:${CLEAR}"
  echo "${GREEN}👉 ${link}${CLEAR}"
  echo
  if ! BORDER0_TOKEN="${BORDER0_TOKEN}" border0 connector start; then
    echo "${BG_RED}⛔️ Something went wrong...${CLEAR}"
    echo "${YELLOW}Please reach out https://docs.border0.com/docs/getting-help, we'd love to learn about your experience${CLEAR}"
    exit 1
  fi
}

install_border0_connector_in_aws() {
  [ $DEBUG = true ] && print_in_box "Install Border0 Connector" "$BG_BLUE"

  CONNECTOR_INSTALL_CMD="border0 connector install --aws --invite ${INVITE_CODE}"
  [ $DEBUG = true ] && echo "${GREEN}Executing>> ${CONNECTOR_INSTALL_CMD}${CLEAR}"

  $CONNECTOR_INSTALL_CMD || exit 1
}

install_border0_connector_as_superuser() {
  [ $DEBUG = true ] && print_in_box "Install Border0 Connector" "$BG_BLUE"

  if [ -z "${I_AM_GROOT:-}" ]; then
    detect_root
  fi

  CONNECTOR_INSTALL_CMD="border0 connector install --daemon-only --token ${BORDER0_TOKEN}"
  CONNECTOR_INSTALL_CMD_TO_PRINT="border0 connector install --daemon-only --token <border0_token>"
  if [ "$I_AM_GROOT" = True ]; then
    [ $DEBUG = true ] && echo "${GREEN}Executing>> ${CONNECTOR_INSTALL_CMD_TO_PRINT}${CLEAR}"
    $CONNECTOR_INSTALL_CMD || return 1
  else
    detect_sudo
    if [ "$EXEC_ELEVATION_CMD" = "sudo" ]; then
      [ $DEBUG = true ] && echo "${GREEN}Executing>> sudo ${CONNECTOR_INSTALL_CMD_TO_PRINT}${CLEAR}"
      # shellcheck disable=SC2086
      sudo $CONNECTOR_INSTALL_CMD || return 1
    elif [ "$EXEC_ELEVATION_CMD" = "su" ]; then
      [ $DEBUG = true ] && echo "${GREEN}Executing>> su -l root bash -c \"${CONNECTOR_INSTALL_CMD}${CLEAR}\""
      printf "Please provide root "
      su -l root bash -c "$CONNECTOR_INSTALL_CMD" || return 1
    fi
  fi

  return 0
}

print_in_box() {
  local string color
  string="$1"
  color="${2:-}"

  local additional_length non_ascii_chars
  additional_length=0
  non_ascii_chars=$(printf "%s" "$string" | LC_ALL=C tr -cd '\200-\377')

  if [ -n "$non_ascii_chars" ]; then
    # string contains non-ascii characters, eg. emojis
    additional_length=1
  fi

  local length begin end
  length=$(($(printf "%s" "$string" | wc -m) + 2 + additional_length))
  begin=""
  end=""

  if [ -n "$color" ]; then
    begin="${color}"
    end="${CLEAR}"
  fi

  printf "${begin}+%s+${end}\n" "$(repeat_string '-' "$length")"
  printf "${begin}| %s |${end}\n" "$string"
  printf "${begin}+%s+${end}\n" "$(repeat_string '-' "$length")"
}

repeat_string() {
  local string number_to_repeat
  string="$1"
  number_to_repeat="$2"

  if [ -n "${string}" ] && [ "$(is_positive_integer "${number_to_repeat}")" = 'true' ]
  then
    local reuslt
    result="$(printf "%${number_to_repeat}s")"
    echo "$result" | sed "s/ /${string}/g"
  fi
}

is_positive_integer() {
  local string
  string="${1}"

  if expr "$string" : "^[1-9][0-9]*$" > /dev/null; then
    echo 'true' && return 0
  fi

  echo 'false' && return 1
}

spinner() {
  # No-op when not a real terminal or tput is unavailable
  if ! [ -t 1 ] || ! command -v tput >/dev/null 2>&1 || [ -z "${TERM:-}" ]; then
    return 0
  fi

  local spinner_clear spinner_symbols spinner_ppid spinner_parentup

  spinner_clear=1
  spinner_symbols="⣷ ⣯ ⣟ ⡿ ⢿ ⣻ ⣽ ⣾"

  # Get the parent PID
  spinner_ppid=$(ps -p "$$" -o ppid=)
  while :; do
    tput civis
    for c in ${spinner_symbols}; do
      tput sc                # save cursor position
      env printf "${c} ${1}" # print the spinner
      tput rc                # restore cursor position
      if [ -f "${SPINNER_DONEFILE}" ]; then
        if [ ${spinner_clear} -eq 1 ]; then
          tput el            # clear to end of line
        fi
        rm "${SPINNER_DONEFILE}"
        break 2
      fi
      # This is questionable. sleep with fractional seconds is not
      # always available, but seems to not break things, when not.
      env sleep .2 # sleep 200ms
      # Check to be sure parent is still going; handles sighup/kill
      if [ -n "$spinner_ppid" ]; then
        # This is ridiculous. ps prepends a space in the ppid call, which breaks
        # this ps with a "garbage option" error.
        # XXX Potential gotcha if ps produces weird output.
        # shellcheck disable=SC2086
        spinner_parentup=$(ps --no-headers $spinner_ppid 2>/dev/null)
        if [ -z "$spinner_parentup" ]; then
          break 2
        fi
      fi
    done
  done
  tput cnorm # make the cursor visible again
  return 0
}

spinner_cleanup() {
  touch "$SPINNER_DONEFILE"
  tput rc 2>/dev/null || true
  tput cnorm 2>/dev/null || true
  tput sgr0 2>/dev/null || true
  return 1
}

spinner_macos_cleanup() {
  if [ "$(uname)" = "Darwin" ]; then
    tput cnorm 2>/dev/null || true
    rm -f "$SPINNER_DONEFILE"
  fi
}

main() {
  parse_arguments "$@"

  define_some_colors
  detect_os
  detect_download_cmd
  if [ $DEBUG = true ]; then
    echo
  fi

  hash border0 2> /dev/null || {
    if [ $DEBUG = true ]; then
      print_in_box "Install Border0 CLI" "$BG_BLUE"
    fi

    detect_root
    detect_arch
    generate_download_url

    # ======================================================================================
    # show a spinner while downloading the binary, so the user knows something is happening
    # ======================================================================================
    SPINNER_DONEFILE="${TMPDIR:-/tmp}/border0stopspinning"
    trap spinner_cleanup INT QUIT TERM     # tries to catch any exit, to reset cursor
    spinner "Downloading Border0 CLI..." & # start the spinner
    download_border0_cli                   # download the binary
    touch "$SPINNER_DONEFILE"              # stop the spinner
    trap - INT QUIT TERM                   # remove the trap
    spinner_macos_cleanup                  # clean up spinner for macOS

    install_border0_cli
    if [ $DEBUG = true ]; then
      echo
    fi
  }

  if [ $AWS = true ]; then
    install_border0_connector_in_aws
  else
    invite_to_connector_token
    if [ $DEBUG = true ]; then
      echo
    fi
    install_border0_connector
  fi
}

main "$@"
