#!/bin/sh
set -e

reset="\033[0m"
red="\033[31m"
green="\033[32m"
yellow="\033[33m"
cyan="\033[36m"
white="\033[37m"
gpg_key=23E7166788B63E1E

yarn_get_tarball() {
  printf "$cyan> Downloading tarball...$reset\n"
  if [ "$1" = '--nightly' ]; then
    url=https://nightly.yarnpkg.com/latest.tar.gz
  elif [ "$1" = '--rc' ]; then
    url=https://yarnpkg.com/latest-rc.tar.gz
  elif [ "$1" = '--version' ]; then
    # Validate that the version matches MAJOR.MINOR.PATCH to avoid garbage-in/garbage-out behavior
    version=$2
    if echo $version | grep -qE "^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+$"; then
      url="https://yarnpkg.com/downloads/$version/yarn-v$version.tar.gz"
    else
      printf "$red> Version number must match MAJOR.MINOR.PATCH.$reset\n"
      exit 1;
    fi
  else
    url=https://yarnpkg.com/latest.tar.gz
  fi
  # Get both the tarball and its GPG signature
  tarball_tmp=`mktemp -t yarn.tar.gz.XXXXXXXXXX`
  if curl --fail -L -o "$tarball_tmp#1" "$url{,.asc}"; then
    yarn_verify_integrity $tarball_tmp

    printf "$cyan> Extracting to ~/.yarn...$reset\n"
    # All this dance is because `tar --strip=1` does not work everywhere
    temp=$(mktemp -d yarn.XXXXXXXXXX)
    tar zxf $tarball_tmp -C "$temp"
    mkdir .yarn
    mv "$temp"/*/* .yarn
    rm -rf "$temp"
    rm $tarball_tmp*
  else
    printf "$red> Failed to download $url.$reset\n"
    exit 1;
  fi
}

# Verifies the GPG signature of the tarball
yarn_verify_integrity() {
  # Check if GPG is installed
  if [[ -z "$(command -v gpg)" ]]; then
    printf "$yellow> WARNING: GPG is not installed, integrity can not be verified!$reset\n"
    return
  fi

  if [ "$YARN_GPG" == "no" ]; then
    printf "$cyan> WARNING: Skipping GPG integrity check!$reset\n"
    return
  fi

  printf "$cyan> Verifying integrity...$reset\n"
  # Grab the public key if it doesn't already exist
  gpg --list-keys $gpg_key >/dev/null 2>&1 || (curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --import)

  if [ ! -f "$1.asc" ]; then
    printf "$red> Could not download GPG signature for this Yarn release. This means the release can not be verified!$reset\n"
    yarn_verify_or_quit "> Do you really want to continue?"
    return
  fi

  # Actually perform the verification
  if gpg --verify "$1.asc" $1; then
    printf "$green> GPG signature looks good$reset\n"
  else
    printf "$red> GPG signature for this Yarn release is invalid! This is BAD and may mean the release has been tampered with. It is strongly recommended that you report this to the Yarn developers.$reset\n"
    yarn_verify_or_quit "> Do you really want to continue?"
  fi
}

yarn_link() {
  printf "$cyan> Adding to \$PATH...$reset\n"
  YARN_PROFILE="$(yarn_detect_profile)"
  SOURCE_STR="\nexport PATH=\"\$HOME/.yarn/bin:\$HOME/.config/yarn/global/node_modules/.bin:\$PATH\"\n"

  if [ -z "${YARN_PROFILE-}" ] ; then
    printf "$red> Profile not found. Tried ${YARN_PROFILE} (as defined in \$PROFILE), ~/.bashrc, ~/.bash_profile, ~/.zshrc, and ~/.profile.\n"
    echo "> Create one of them and run this script again"
    echo "> Create it (touch ${YARN_PROFILE}) and run this script again"
    echo "   OR"
    printf "> Append the following lines to the correct file yourself:$reset\n"
    command printf "${SOURCE_STR}"
  else
    if ! grep -q 'yarn/bin' "$YARN_PROFILE"; then
      if [[ $YARN_PROFILE == *"fish"* ]]; then
        command fish -c 'set -U fish_user_paths $fish_user_paths ~/.yarn/bin'
        printf "$cyan> We've added ~/.yarn/bin to your fish_user_paths universal variable\n"
      else
        command printf "$SOURCE_STR" >> "$YARN_PROFILE"
        printf "$cyan> We've added the following to your $YARN_PROFILE\n"
      fi
      
      echo "> If this isn't the profile of your current shell then please add the following to your correct profile:"
      printf "   $SOURCE_STR$reset\n"
    fi

    version=`$HOME/.yarn/bin/yarn --version` || (
      printf "$red> Yarn was installed, but doesn't seem to be working :(.$reset\n"
      exit 1;
    )

    printf "$green> Successfully installed Yarn $version! Please open another terminal where the \`yarn\` command will now be available.$reset\n"
  fi
}

yarn_detect_profile() {
  if [ -n "${PROFILE}" ] && [ -f "${PROFILE}" ]; then
    echo "${PROFILE}"
    return
  fi

  local DETECTED_PROFILE
  DETECTED_PROFILE=''
  local SHELLTYPE
  SHELLTYPE="$(basename "/$SHELL")"

  if [ "$SHELLTYPE" = "bash" ]; then
    if [ -f "$HOME/.bashrc" ]; then
      DETECTED_PROFILE="$HOME/.bashrc"
    elif [ -f "$HOME/.bash_profile" ]; then
      DETECTED_PROFILE="$HOME/.bash_profile"
    fi
  elif [ "$SHELLTYPE" = "zsh" ]; then
    DETECTED_PROFILE="$HOME/.zshrc"
  elif [ "$SHELLTYPE" = "fish" ]; then
    DETECTED_PROFILE="$HOME/.config/fish/config.fish"
  fi

  if [ -z "$DETECTED_PROFILE" ]; then
    if [ -f "$HOME/.profile" ]; then
      DETECTED_PROFILE="$HOME/.profile"
    elif [ -f "$HOME/.bashrc" ]; then
      DETECTED_PROFILE="$HOME/.bashrc"
    elif [ -f "$HOME/.bash_profile" ]; then
      DETECTED_PROFILE="$HOME/.bash_profile"
    elif [ -f "$HOME/.zshrc" ]; then
      DETECTED_PROFILE="$HOME/.zshrc"
    elif [ -f "$HOME/.config/fish/config.fish" ]; then
      DETECTED_PROFILE="$HOME/.config/fish/config.fish"
    fi
  fi

  if [ ! -z "$DETECTED_PROFILE" ]; then
    echo "$DETECTED_PROFILE"
  fi
}

yarn_reset() {
  unset -f yarn_install yarn_reset yarn_get_tarball yarn_link yarn_detect_profile yarn_verify_integrity yarn_verify_or_quit
}

yarn_install() {
  printf "${white}Installing Yarn!$reset\n"

  if [ -d "$HOME/.yarn" ]; then
    if which yarn; then
      local latest_url
      local specified_version
      local version_type
      if [ "$1" = '--nightly' ]; then
        latest_url=https://nightly.yarnpkg.com/latest-tar-version
        specified_version=`curl -sS $latest_url`
        version_type='latest'
      elif [ "$1" = '--version' ]; then
        specified_version=$2
        version_type='specified'
      elif [ "$1" = '--rc' ]; then
        latest_url=https://yarnpkg.com/latest-rc-version
        specified_version=`curl -sS $latest_url`
        version_type='rc'
      else
        latest_url=https://yarnpkg.com/latest-version
        specified_version=`curl -sS $latest_url`
        version_type='latest'
      fi
      yarn_version=`yarn -V`
      yarn_alt_version=`yarn --version`

      if [ "$specified_version" = "$yarn_version" -o "$specified_version" = "$yarn_alt_version" ]; then
        printf "$green> Yarn is already at the $specified_version version.$reset\n"
        exit 0
      else
      	printf "$yellow> $yarn_alt_version is already installed, Specified version: $specified_version.$reset\n"
        rm -rf "$HOME/.yarn"
      fi
    else
      printf "$red> $HOME/.yarn already exists, possibly from a past Yarn install.$reset\n"
      printf "$red> Remove it (rm -rf $HOME/.yarn) and run this script again.$reset\n"
      exit 0
    fi
  fi

  yarn_get_tarball $1 $2
  yarn_link
  yarn_reset
}

yarn_verify_or_quit() {
  read -p "$1 [y/N] " -n 1 -r
  echo
  if [[ ! $REPLY =~ ^[Yy]$ ]]
  then
    printf "$red> Aborting$reset\n"
    exit 1
  fi
}

cd ~
yarn_install $1 $2
