#!/bin/sh

if [ "$REACH_DEBUG" = "Y" ] ; then
  set -x
fi

if [ ! "$REACH_ALLOW_SU" = '1' ] && [ "$(id -u)" -eq 0 ]; then
  echo "Reach isn't intended to be run with superuser privileges."
  echo
  echo "Please try again while logged into a normal, non-root account, and without using \
\`sudo\`, \`su\`, or \`doas\` to grant elevated permissions."
  echo
  case "$(uname -s)" in
    Linux)
      if ! (groups "$(logname)" 2>&1 | grep -q docker 2>/dev/null); then
        echo "Adding your account to the \`docker\` group should make this possible:"
        echo "https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user"
        echo
        echo "Once you've done this, make sure to log out and back in before retrying."
        echo
      else
        echo "Try logging out and back in if you've recently made yourself a member of the \`docker\` group but are unable to run Reach without \`sudo\`."
        echo
      fi
      ;;
    *) : ;; # Docker Desktop for macOS doesn't use the `docker` group
  esac
  exit 1
fi

if [ -n "$DOCKER_HOST" ] && ! (echo "$DOCKER_HOST" | grep -q '^unix:'); then
  echo "Reach only supports connecting to Docker via a local UNIX socket."
  echo
  echo "Please follow the directions from the link below to \`unset DOCKER_HOST\` or explicitly override it, e.g.:"
  echo " $ DOCKER_HOST= $0 $*"
  echo
  echo "https://docs.docker.com/engine/install/linux-postinstall/#cannot-connect-to-the-docker-daemon"
  echo
  exit 1
fi

IMG='reachsh/reach-cli:latest'
TMP=$(mkdir -p /tmp/reach/cli; mktemp -d "/tmp/reach/cli/$(date -u '+%Y-%m-%dT%H-%M-%SZ')-XXXX")
CNF="${XDG_CONFIG_HOME:-$HOME/.config}/reach"; CNF="$(mkdir -p "$CNF" && cd "$CNF" && pwd)"
MD5=md5sum; if [ ! "$(command -v $MD5)" ]; then MD5=md5; fi
RCI=$(head -n1 /dev/urandom | $MD5 | head -c 30 | tr '[:lower:]' '[:upper:]')
export TMP

if [ ! -e "$CNF/env" ]; then
  echo "# Automatically generated with \`reach\` script at $(date -u '+%Y-%m-%dT%H:%M:%S.%NZ')" > "$CNF/env"
  echo "export REACHC_ID=$RCI" >> "$CNF/env"
elif ! grep REACHC_ID "$CNF/env" > /dev/null 2>&1; then
  mkdir -p "$CNF/_backup"
  cp "$CNF/env" "$CNF/_backup/env-$(date -u '+%Y-%m-%dT%H:%M:%S.%NZ')"
  printf '\nexport REACHC_ID=%s\n' "$RCI" >> "$CNF/env"
fi

if [ -z "$REACH_ENV_PRS" ] && [ -f "$CNF/env" ]; then
  e="$(env |grep '^REACH')"
  # shellcheck disable=SC1090,SC1091
  . "$CNF/env"
  for l in $e; do export "${l?}"; done
  export REACH_ENV_PRS=1 # Prevent recursive sourcing
fi

run_d () {
  REACH_HS="$(cd "$(dirname "$0")" && pwd)/hs"
  export REACH_DIR_EMBED="${REACH_DIR_EMBED:-"$(cd "$(dirname "$0")" && pwd)/hs/app/reach/embed"}"
  export REACH_STACK_YAML="${REACH_STACK_YAML:-"$(cd "$(dirname "$0")" && pwd)/hs/stack.yaml"}"

  if  [ "$REACH_DOCKER" = "0"  ] \
   && [ -d "$REACH_DIR_EMBED"  ] \
   && [ -f "$REACH_STACK_YAML" ] \
   && which stack >/dev/null 2>&1; then
    (cd "$REACH_HS" && make -s hs-build 1>&2) \
      && REACH_EX="$0" "$(stack --stack-yaml "$REACH_STACK_YAML" exec -- which reach 2>/dev/null)" \
        --dir-embed="$REACH_DIR_EMBED" \
        --dir-project-container="$(pwd)" \
        --dir-project-host="$(pwd)" \
        --dir-tmp-container="$TMP" \
        --dir-tmp-host="$TMP" \
        --dir-config-container="$CNF" \
        --dir-config-host="$CNF" \
        "$@"
  else
    cid="$(docker ps -f "ancestor=$IMG" --format '{{.ID}} {{.Labels}}' \
      | grep -e "sh.reach.dir-project=$(pwd)\$" \
             -e "sh.reach.dir-project=$(pwd)," \
      | awk '{print $1}' \
      | head -n1)"

    if [ -z "$cid" ]; then
      cid="$(docker run -d --rm \
        -v "$(pwd):/app/src" \
        -v "$(dirname "$(dirname "$TMP")"):/app/tmp" \
        -v "$CNF:/app/config" \
        -l "sh.reach.dir-project=$(pwd)" \
        -u "$(id -ru):$(id -rg)" \
        --name "reach-cli-$$" \
        --entrypoint tail \
        $IMG -f /dev/null)"
    fi

    docker exec -i \
      -e "REACH_EX=$0" \
      -e "REACH_CONNECTOR_MODE" \
      -e "REACH_DEBUG" \
      -e "REACH_IDE" \
      -e "REACH_RPC_KEY" \
      -e "REACH_RPC_PORT"  \
      -e "REACH_RPC_SERVER" \
      -e "REACH_RPC_TLS_CRT" \
      -e "REACH_RPC_TLS_KEY" \
      -e "REACH_RPC_TLS_PASSPHRASE" \
      -e "REACH_RPC_TLS_REJECT_UNVERIFIED" \
      -e "REACH_VERSION" \
      -e "CI" \
      -e "SHELL" \
      -u "$(id -ru):$(id -rg)" \
      "$cid" reach \
        --dir-project-host="$(pwd)" \
        --dir-tmp-container="/app/tmp$(echo "$TMP" | sed "s|$(dirname "$(dirname "$TMP")")||")" \
        --dir-tmp-host="$TMP" \
        --dir-config-host="$CNF" \
        "$@"
  fi
}

run_s () {
  chmod 700 "$TMP/out.sh"
  sh -ac "$TMP/out.sh" "$0"
}

call_home () {
CALL_HOME_ENCODED="eyJ1c2VySWQiOiJ7e1JFQUNIQ19JRH19\
Iiwic3RhcnRUaW1lIjoie3tTVEFSVF9USU1FfX0iLCJy\
ZXN1bHQiOiJ7e1JFU1VMVH19IiwidmVyc2lvbiI6Int7\
UkVBQ0hfVkVSU0lPTn19IiwiY29ubmVjdG9yTW9kZSI6\
Int7Q09OTkVDVE9SX01PREV9fSIsInVzaW5nVmlzdWFs\
U3R1ZGlvRXh0ZW5zaW9uIjoie3tVU0lOR19WU1NUVURJ\
T19FWFRFTlNJT059fSIsImluaXRpYXRvciI6Int7SU5JVElBVE9SfX0ifQ=="

  CALL_HOME_TEMPLATE_DECODED=$(printf '%s' "$CALL_HOME_ENCODED" | base64 -d)
  TRANSLATED_TEMPLATE=$(echo "${CALL_HOME_TEMPLATE_DECODED}" | sed -e "s/{{REACHC_ID}}/$REACHC_ID/g" \
    -e "s/{{START_TIME}}/$(date -u +"%Y-%m-%d")/g" \
    -e "s/{{RESULT}}/$1/g" \
    -e "s/{{REACH_VERSION}}/$2/g" \
    -e "s/{{CONNECTOR_MODE}}/$3/g" \
    -e "s/{{USING_VSSTUDIO_EXTENSION}}/$4/g" \
    -e "s/{{INITIATOR}}/$5/g")
  curl -X POST "https://log.reach.sh/submit" -d "$TRANSLATED_TEMPLATE" || exit 1
}

package_install () {
  if ( command -v apt > /dev/null 2>&1 ); then
    PACKAGE_MANAGER="apt"
  fi

  if ( command -v yum > /dev/null 2>&1 ); then
    PACKAGE_MANAGER="yum"
  fi

  sudo ${PACKAGE_MANAGER} install "${1}"
}

timeout_validate () {
  if [ "$2" -eq "$1" ]; then
    printf "%s" "$3"
    exit 1
  fi
}

install_docker () {
  OPWD=$(pwd)
  cd / # Depending on `$PWD`, Windows sometimes struggles with paths
  if (command -v wsl.exe > /dev/null 2>&1); then
    if (! command -v winget.exe > /dev/null 2>&1); then
      printf "Installing Winget Windows Package Manager..."
      WINGET_VERSION="v1.3.431"
      WINGET_ARTIFACT_NAME="Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle"
      WINGET_BUNDLE_URL="https://github.com/microsoft/winget-cli/releases/download/${WINGET_VERSION}/${WINGET_ARTIFACT_NAME}"
      TEMP_DIR="/mnt/c/tmp"
      WIN_TEMP_DIR="c:\\tmp"
      DOCKER_BIN="/mnt/c/Program Files/Docker/Docker/resources/bin/docker"
      mkdir -p $TEMP_DIR
      sudo wget $WINGET_BUNDLE_URL -O "${TEMP_DIR}/${WINGET_ARTIFACT_NAME}"; powershell.exe "cd ${WIN_TEMP_DIR}; powershell .\\${WINGET_ARTIFACT_NAME}"
      STOPPER=0
      while ( ! command -v winget.exe > /dev/null 2>&1 ); do
        sleep 1;
        STOPPER=$((STOPPER + 1))
        timeout_validate 180 "${STOPPER}" "Winget wasn't installed successfully and timed out!\n"
      done
      rm -rf "${TEMP_DIR:?}/${WINGET_ARTIFACT_NAME}"
    fi
    printf "\nInstalling Docker through Winget..."
    powershell.exe 'Start-Process powershell.exe "winget install docker.dockerdesktop --accept-package-agreements --accept-source-agreements" -Verb runAs'
    STOPPER=0
    while [ ! -f "${DOCKER_BIN}" ]; do
      sleep 120;
      STOPPER=$((STOPPER + 1))
      timeout_validate 6 "${STOPPER}" "Docker wasn't installed successfully and timed out!\n"
    done
    printf "\nThis installation requires a restart for completion; do you want to restart now? [Y,n]: "
    read -r RESPONSE
    if [ "${RESPONSE}" = "Y" ]; then
      call_home "Docker installed by Reach" "0.0.0" "none" "false" "script_deps"
      powershell.exe 'shutdown -r -t 0'
    fi
  else
    printf "Make sure you have Docker installed following these steps:\n"
    printf "Ubuntu: https://docs.docker.com/engine/install/ubuntu/\n"
    printf "Debian: https://docs.docker.com/engine/install/debian/\n"
    printf "CentOS: https://docs.docker.com/engine/install/centos/\n"
    printf "Fedora: https://docs.docker.com/engine/install/fedora/\n"
    printf "RedHat: https://docs.docker.com/engine/install/rhel/\n"
    printf "  SLES: https://docs.docker.com/engine/install/SLES/\n"
  fi
  # shellcheck disable=SC2164
  cd "${OPWD}"
}

for DEP in curl make docker docker-compose; do
  if ! (command -v "${DEP}" >/dev/null 2>&1); then
    if [ "${DEP}" != "curl" ]; then
      call_home "$DEP is not installed" "0.0.0" "none" "false" "script_deps"
    fi
    printf "Reach relies on an installation of %s; do you want to install it? [Y,n]: " "${DEP}"
    read -r RESPONSE
    if [ "${RESPONSE}" = "Y" ]; then
      case $DEP in
        "docker") install_docker;;
               *) package_install $DEP;;
      esac
    fi
  fi
done

if [ ! "$CIRCLECI" = "true" ] && [ "$(docker image ls -q $IMG)" = '' ]; then
  if ! docker pull "$IMG"; then exit 1; fi
fi

run_d "$@"
case "$?" in
  42) run_s; case "$?" in
    60) rm -r "$TMP" && exit 60 ;; # Updates available
     0) [ -d "$TMP" ] && rm -r "$TMP"; exit 0 ;;
     *) [ -z "$(ls -A "$TMP")" ] && rm -r "$TMP"; exit 1 ;;
    esac
    ;;
  50) docker pull "$IMG" && curl https://docs.reach.sh/reach -o "$0" && chmod +x "$0" && rm -r "$TMP" && exit 0 ;;
  60) rm -r "$TMP" && exit 60 ;; # Updates available
   0) rm -r "$TMP" ;;
   *) [ -z "$(ls -A "$TMP")" ] && rm -r "$TMP"; exit 1 ;;
esac
