#!/usr/bin/env bash

usage()
{
cat << EOF
GYB installation script.

OPTIONS:
   -h      show help.
   -d      Directory where gyb folder will be installed. Default is \$HOME/bin/
   -a      Architecture to install (i686, x86_64, armv7l, aarch64). Default is to detect your arch with "uname -m".
   -o      OS we are running (linux, osx). Default is to detect your OS with "uname -s".
   -l      Just upgrade GYB to latest version. Skips project creation and auth.
   -p      Profile update (true, false). Should script add gyb command to environment. Default is true.
   -u      Admin user email address to use with GYB. Default is to prompt.
   -r      Regular user email address. Used to test service account access to user data. Default is to prompt.
   -v      Version to install (latest, prerelease, draft, 3.8, etc). Default is latest.
EOF
}


target_dir="$HOME/bin"
myarch=$(uname -m)
myos=$(uname -s)
osversion=""
update_profile=true
upgrade_only=false
gybversion="latest"
adminuser=""
regularuser=""
glibc_vers="2.31"

while getopts "hd:a:o:b:lp:u:r:v:" OPTION
do
     case $OPTION in
         h) usage; exit;;
         d) target_dir="$OPTARG";;
         a) myarch="$OPTARG";;
         o) myos="$OPTARG";;
         b) osversion="$OPTARG";;
         l) upgrade_only=true;;
         p) update_profile="$OPTARG";;
         u) adminuser="$OPTARG";;
         r) regularuser="$OPTARG";;
         v) gybversion="$OPTARG";;
         ?) usage; exit;;
     esac
done

# remove possible / from end of target_dir
target_dir=${target_dir%/}

update_profile() {
	[ -f "$1" ] || return 1

	grep -F "$alias_line" "$1" > /dev/null 2>&1
	if [ $? -ne 0 ]; then
                echo_yellow "Adding gyb alias to profile file $1."
		echo -e "\n$alias_line" >> "$1"
        else
          echo_yellow "gyb alias already exists in profile file $1. Skipping add."
	fi
}

echo_red()
{
echo -e "\x1B[1;31m$1"
echo -e '\x1B[0m'
}

echo_green()
{
echo -e "\x1B[1;32m$1"
echo -e '\x1B[0m'
}

echo_yellow()
{
echo -e "\x1B[1;33m$1"
echo -e '\x1B[0m'
}

version_gt()
{
# MacOS < 10.13 doesn't support sort -V
echo "" | sort -V > /dev/null 2>&1
vsort_failed=$?
if [ "${1}" = "${2}" ]; then
  true
elif (( $vsort_failed != 0 )); then
  false
else
  test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"
fi
}

case $myos in
  [lL]inux)
    myos="linux"
    this_glibc_ver=$(ldd --version | awk '/ldd/{print $NF}')
    echo "This Linux distribution uses glibc $this_glibc_ver"
    useglibc="legacy"
    for glibc_ver in $glibc_vers; do
      if version_gt $this_glibc_ver $glibc_ver; then
        useglibc="glibc$glibc_ver"
        echo_green "Using GYB compiled against $useglibc"
        break
      fi
    done
    case $myarch in
      x86_64) gybfile="linux-x86_64-$useglibc.tar.xz";;
      arm64|aarch64) gybfile="linux-aarch64-$useglibc.tar.xz";;
      *)
        echo_red "ERROR: this installer currently only supports x86_64 and aarch64 architectures. Looks like you're running on $myarch. You'll need to try the Python source. Exiting."
        exit
    esac
    ;;
  [Mm]ac[Oo][sS]|[Dd]arwin)
    if [ "$osversion" == "" ]; then
      this_macos_ver=$(sw_vers -productVersion)
    else
      this_macos_ver=$osversion
    fi
    echo_green "You are running MacOS ${this_macos_ver} on ${myarch}"
    case $myarch in
      x86_64) gybfile="macos-x86_64.tar.xz";;
      arm64|aarch64) gybfile="macos-aarch64.tar.xz";;
      *)
        echo_red "ERROR: this installer currently suppports x86_64 and aarch64 architectures. Looks like you're running on $myarch. Exiting"
	exit
    esac
    ;;
  *)
    echo_red "Sorry, this installer currently only supports Linux and MacOS. Looks like you're runnning on $myos. Exiting."
    exit
    ;;
esac

if [ "$gybversion" == "latest" -o "$gybversion" == "prerelease" -o "$gybversion" == "draft" ]; then
  release_url="https://api.github.com/repos/GAM-team/got-your-back/releases"
else
  release_url="https://api.github.com/repos/GAM-team/got-your-back/releases/tags/v$gybversion"
fi

if [ -z ${GHCLIENT+x} ]; then
  check_type="unauthenticated"
else
  check_type="authenticated"
fi

echo_yellow "Checking GitHub URL $release_url for $gybversion GYB release ($check_type)..."
release_json=$(curl -s $GHCLIENT $release_url 2>&1 /dev/null)

echo_yellow "Getting file and download URL..."
# Python is sadly the nearest to universal way to safely handle JSON with Bash
# At least this code should be compatible with just about any Python version ever
# unlike GYB itself. If some users don't have Python we can try grep / sed / etc
# but that gets really ugly
pycode="import json
import sys

attrib = sys.argv[1]
gybversion = sys.argv[2]

release = json.load(sys.stdin)
if type(release) is list:
  for a_release in release:
    if a_release['prerelease'] and gybversion != 'prerelease':
      continue
    elif a_release['draft'] and gybversion != 'draft':
      continue
    release = a_release
    break
try:
  for asset in release['assets']:
    if asset[attrib].endswith('$gybfile'):
      print(asset[attrib])
      break
  else:
    print('ERROR: Attribute: {0} for $gybfile version {1} not found'.format(attrib, gybversion))
except KeyError:
  print('ERROR: assets value not found in JSON value of:\n\n%s' % release)"

pycmd="python3"
$pycmd -V >/dev/null 2>&1
rc=$?
if (( $rc != 0 )); then
  pycmd="python"
fi
$pycmd -V >/dev/null 2>&1
rc=$?
if (( $rc != 0 )); then
  echo_red "ERROR: No version of python installed."
  exit
fi

browser_download_url=$(echo "$release_json" | $pycmd -c "$pycode" browser_download_url $gybversion)
if [[ ${browser_download_url:0:5} = "ERROR" ]]; then
  echo_red "${browser_download_url}"
  exit
fi
name=$(echo "$release_json" | $pycmd -c "$pycode" name $gybversion)
if [[ ${name:0:5} = "ERROR" ]]; then
  echo_red "${name}"
  exit
fi
# Temp dir for archive
temp_archive_dir=$(mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir')
echo_yellow "Downloading file $name from $browser_download_url to $temp_archive_dir ($check_type)..."
# Save archive to temp w/o losing our path
(cd $temp_archive_dir && curl -O -L $GHCLIENT $browser_download_url)

mkdir -p "$target_dir"

echo_yellow "Extracting archive to $target_dir"
tar xf $temp_archive_dir/$name -C "$target_dir"
rc=$?
if (( $rc != 0 )); then
  echo_red "ERROR: extracting the GYB archive with tar failed with error $rc. Exiting."
  exit
else
  echo_green "Finished extracting GYB archive."
fi

if [ "$upgrade_only" = true ]; then
  echo_green "Here's information about your GYB upgrade:"
  "$target_dir/gyb/gyb" --version
  rc=$?
  if (( $rc != 0 )); then
    echo_red "ERROR: Failed running GYB for the first time with $rc. Please report this error to GYB mailing list. Exiting."
    exit
  fi

  echo_green "GYB upgrade complete!"
  exit
fi

# Update profile to add gyb command
if [ "$update_profile" = true ]; then
  alias_line="export PATH=$PATH:$target_dir/gyb"
  if [ "$myos" == "linux" ]; then
    update_profile "$HOME/.bashrc" || update_profile "$HOME/.bash_profile"
  elif [ "$myos" == "osx" ]; then
    update_profile "$HOME/.profile" || update_profile "$HOME/.bash_profile"
  fi
else
  echo_yellow "skipping profile update."
fi

while [ ! -f "$target_dir/gyb/nobrowser.txt" ]; do
  read -p "Can you run a full browser on this machine? (usually Y for MacOS, N for Linux if you SSH into this machine) " yn
  case $yn in
    [Yy]*)
      break
      ;;
    [Nn]*)
      touch "$target_dir/gyb/nobrowser.txt" > /dev/null 2>&1
      break
      ;;
    *)
      echo_red "Please answer yes or no."
      ;;
  esac
done
echo

if [ "$adminuser" == "" ]; then
  read -p "Please enter your email address: " adminuser
fi

project_created=false
while true; do
  "$target_dir/gyb/gyb" --action create-project --email $adminuser
  rc=$?
  if (( $rc == 0 )); then
    echo_green "Project creation complete."
    project_created=true
    break
  else
    echo_red "Project creation failed. Trying again."
  fi
done

admin_authorized=false
while true; do
  read -p "Do you want to authorize GYB to backup email for $adminuser? (yes or no) " yn
  case $yn in
    [Yy]*)
      "$target_dir/gyb/gyb" --action quota --email $adminuser
      rc=$?
      if (( $rc == 0 )); then
        echo_green "User authorization complete."
        admin_authorized=true
        break
      else
        echo_red "User authorization failed. Trying again. Say N to skip user authorization."
      fi
      ;;
     [Nn]*)
       echo -e "\nYou can authorize a user later by running:\n\ngyb --action quota --email $adminuser\n"
       break
       ;;
     *)
       echo_red "Please answer yes or no."
       ;;
  esac
done

service_account_authorized=false
while $project_created; do
  read -p "Are you ready to authorize GYB to backup and restore G Suite user email? (yes or no) " yn
  case $yn in
    [Yy]*)
      if [ "$regularuser" == "" ]; then
        read -p "Please enter the email address of a regular G Suite user: " regularuser
      fi
      echo_yellow "Great! Checking service account scopes.This will fail the first time. Follow the steps to authorize and retry. It can take a few minutes for scopes to PASS after they've been authorized in the admin console."
      "$target_dir/gyb/gyb" --email $regularuser --action check-service-account
      rc=$?
      if (( $rc == 0 )); then
        echo_green "Service account authorization complete."
        service_account_authorized=true
        break
      else
        echo_red "Service account authorization failed. Confirm you entered the scopes correctly in the admin console. It can take a few minutes for scopes to PASS after they are entered in the admin console so if you're sure you entered them correctly, go grab a coffee and then hit Y to try again. Say N to skip admin authorization."
      fi
      ;;
     [Nn]*)
       echo -e "\nYou can authorize a service account later by running:\n\ngyb --email $regularuser --action check-service-account\n"
       break
       ;;
     *)
       echo_red "Please answer yes or no."
       ;;
  esac
done

echo_green "Here's information about your new GYB installation:"
"$target_dir/gyb/gyb" --version
rc=$?
if (( $rc != 0 )); then
  echo_red "ERROR: Failed running GYB for the first time with $rc. Please report this error to GYB mailing list. Exiting."
  exit
fi

echo_green "GYB installation and setup complete!"
if [ "$update_profile" = true ]; then
  echo_green "Please restart your terminal shell or to get started right away run:\n\n$target_dir/gyb/gyb"
fi

# Clean up after ourselves even if we are killed with CTRL-C
trap "rm -rf $temp_archive_dir" EXIT