#!/bin/bash

#
# run from curl or local will give different results.
#  curl -fsSL https://raw.githubusercontent.com/aqualinkd/AqualinkD/master/release/remote_install.sh | sudo bash -s -- latest
#  ./upgrade.sh latest
#
# To get good / bad exit code from both curl and bash, use below. It will exit current term so be careful.
# curl -fsSL "https://raw.githubusercontent.com/aqualinkd/AqualinkD/master/release/remote_install.sh" | ( sudo bash && exit 0 ) || exit $?

REQUIRED_SPACE_MB=18 # Need 17MB, use 18

TRUE=0
FALSE=1

REPO="https://api.github.com/repos/AqualinkD/AqualinkD"
#REPO="https://api.github.com/repos/sfeakes/AqualinkD"

INSTALLED_BINARY="/usr/local/bin/aqualinkd"

# Can't use $0 since this script is usually piped into bash
SELF="remote_install.sh"

REL_VERSION=""
DEV_VERSION=""
INSTALLED_VERSION=""

TEMP_INSTALL="/tmp/aqualinkd"
OUTPUT="/tmp/aqualinkd_upgrade.log"

FROM_CURL=$FASE
SYSTEMD_LOG=$FALSE

# Remember not to use (check for terminal, as it may not exist when pipe to bash)
# ie.  if [ -t 0 ]; then  

# We can get called from no path, so find external commands
if command -v "systemd-cat" &>/dev/null; then
  SYSTEMD_LOG=$TRUE
fi


log()
{ 
  echo "$*"

  if [ "$SYSTEMD_LOG" -eq $TRUE ]; then
    # For some unknown reason, only way below works from aqualinkd process is adding "&>> "$OUTPUT""
    echo "Upgrade:   $*" | systemd-cat -t aqualinkd -p info  &>> "$OUTPUT"
  else
    logger -p local0.notice -t aqualinkd "Upgrade:   $*"
  fi

  echo "$*" 2>/dev/null >> "$OUTPUT"
}

logerr()
{ 
  echo "Error: $*" >&2

  logger -p local0.err -t aqualinkd "Upgrade1:   $*" &>> "$OUTPUT"

  if [ "$SYSTEMD_LOG" -eq $TRUE ]; then
    # For some unknown reason, only way below works from aqualinkd process is adding "&>> "$OUTPUT""
    echo "Upgrade:   $*" | systemd-cat -t aqualinkd -p err &>> "$OUTPUT"
  else
    logger -p local0.err -t aqualinkd "Upgrade:   $*"
  fi

  echo "ERROR: $*" 2>/dev/null >> "$OUTPUT"
}


function check_tool() {
  cmd=$1
  if ! command -v "$cmd" &>/dev/null
  then
    log "Command '$cmd' could not be found!"
    return "$FALSE"
  fi

  return "$TRUE"
}

function latest_release_version {
  REL_VERSION=$(curl -fsSL "$REPO/releases/latest" | grep -Po '"tag_name": "\K.*?(?=")')
  if [[ "$REL_VERSION" != "" ]]; then
    return "$TRUE"
  else
    return "$FALSE"
  fi
}

function latest_development_version {
  #DEV_VERSION=$(curl --silent -L "https://raw.githubusercontent.com/sfeakes/AqualinkD/master/version.h" | grep AQUALINKD_VERSION | cut -d '"' -f 2)
  DEV_VERSION=$(curl -fsSL -H "Accept: application/vnd.github.raw" "$REPO/contents/source/version.h" | grep AQUALINKD_VERSION | cut -d '"' -f 2)
  if [[ "$DEV_VERSION" != "" ]]; then
    return "$TRUE"
  else
    return "$FALSE"
  fi
}

function installed_version {
  if [ -f "$INSTALLED_BINARY" ]; then
    if check_tool strings &&
       check_tool grep &&
       check_tool awk &&
       check_tool tr; then
      INSTALLED_VERSION=$(strings "$INSTALLED_BINARY" | grep sw_version | awk -v RS="," -v FS=":" '/sw_version/{print $2;exit;}' | tr -d ' "' )
      log "Current installed version $INSTALLED_VERSION"
    fi
  else
    log "AqualinkD is not installed"
  fi

  if [[ "$INSTALLED_VERSION" != "" ]]; then
    return "$TRUE"
  else
    return "$FALSE"
  fi
}

function check_system_arch {
  ARCH=$(dpkg --print-architecture)

  case $ARCH in 
    arm64 |\
    armhf)
      return "$TRUE"
    ;;
    *)
      logerr "System arch is $ARCH, this is not supported by AqualinkD"
      return "$FALSE";
    ;;
  esac
}


function check_can_upgrade {
  #version=$1
  output=""
  # Check we have needed commands.
  # curl, dpkg, systemctl
  if ! command -v curl &>/dev/null; then output+="Command 'curl' not found, please check it's installed and in path\n"; fi
  if ! command -v dpkg &>/dev/null; then output+="Command 'dpkg' not found, please check it's installed and in path\n"; fi
  if ! command -v systemctl &>/dev/null; then output+="Command 'systemctl' not found, please check it's installed and in path\n"; fi
  
  # Check root is rw
  if mount | grep " / " | grep -q "(ro,"; then
    # check if can remount rw.
    if mount / -o remount,rw &>/dev/null; then
      # can mount RW.
      mount / -o remount,ro &>/dev/null
    else
      output+="Root filesystem is readonly & failed to remount read write, can't upgrade";
    fi
  fi

  # Check we can get the latest version
  if ! latest_release_version; then output+="Couldn't find latest version on github"; fi

   # Check we can get the latest version
  if command -v dpkg &>/dev/null; then
    if ! check_system_arch; then output+="System Architecture not supported!"; fi
  fi

  # Check free diskspace
  mkdir -p "$TEMP_INSTALL"
  free_space_mb=$(df -mP "$TEMP_INSTALL" 2>/dev/null | awk 'NR==2{print $4}' )

  # Check if the df command was successful and if free_space_mb is a number
  if [ -z "$free_space_mb" ] || ! [[ "$free_space_mb" =~ ^[0-9]+$ ]]; then
    output+="Could not retrieve free space for directory: $TEMP_INSTALL"
  else
    if [ "$free_space_mb" -lt "$REQUIRED_SPACE_MB" ]; then
      output+="Not enough disk space on directory: $TEMP_INSTALL! (Required $REQUIRED_SPACE_MB MB)"
    fi
  fi

  if [[ "$output" == "" ]] && [[ "$REL_VERSION" != "" ]]; then 
    return "$TRUE"
  else [[ "$output" != "" ]]
    logerr "$output";
    return "$FALSE"
  fi

  return "$TRUE"
}


function download_latest_release {
  mkdir -p "$TEMP_INSTALL"
  tar_url=$(curl -fsSL "$REPO/releases/latest" | grep -Po '"tarball_url": "\K.*?(?=")')
  if [[ "$tar_url" == "" ]]; then return "$FALSE"; fi

  curl -fsSL "$tar_url" | tar xz --strip-components=1 --directory="$TEMP_INSTALL"
  if [ $? -ne 0 ]; then return "$FALSE"; fi

  return "$TRUE";
}

function download_latest_development {
  mkdir -p "$TEMP_INSTALL"
  tar_url="$REPO/tarball/master"
  curl -fsSL "$tar_url" | tar xz --strip-components=1 --directory="$TEMP_INSTALL"
  if [ $? -ne 0 ]; then return "$FALSE"; fi

  return "$TRUE";
}

function download_version {
  tar_url=$(curl -fsSL "$REPO/releases" | awk 'match($0,/.*"tarball_url": "(.*\/tarball\/.*)".*/)' | grep $1\" | awk -F '"' '{print $4}')
  if [[ ! -n "$tar_url" ]]; then
    return $"$FALSE"
  fi

  mkdir -p "$TEMP_INSTALL"
  curl -fsSL "$tar_url" | tar xz --strip-components=1 --directory="$TEMP_INSTALL"
  if [ $? -ne 0 ]; then return "$FALSE"; fi

  return "$TRUE";
}

function get_all_versions {
  curl -fsSL "$REPO/releases" | awk 'match($0,/.*"tarball_url": "(.*\/tarball\/.*)".*/)' | awk -F '/' '{split($NF,a,"\""); print a[1]}'
}

function run_install_script {
  if [ ! -f "$TEMP_INSTALL/release/install.sh" ]; then
    logerr "Can not find install script $TEMP_INSTALL/release/install.sh"
    return "$FALSE"
  fi

  log "Installing AqualinkD $1"

  # Can't run in background as it'll cleanup / delete files before install.
  temp_file=$(mktemp)
  nohup "$TEMP_INSTALL/release/install.sh" "--logfile" "$temp_file" >> "$OUTPUT" 2>&1
  cat $temp_file
  rm $temp_file

  #nohup "/nas/data/Development/Raspberry/AqualinkD/release/install.sh" >> "$OUTPUT" 2>&1 &
  #nohup "$TEMP_INSTALL/release/install.sh" >> "$OUTPUT" 2>&1 &
}

function remove_install {
  curl -fsSL -H "Accept: application/vnd.github.raw+json" "$REPO/contents/install/install.sh" | sudo bash clean
}

function cleanup {
  rm -rf "$TEMP_INSTALL"
}


####################################################
#
#  Main
#  


# See if we are called from curl or local dir.
# with curl no tty input and script name wil be blank.
if ! tty > /dev/null 2>&1; then
  script=$(basename "$0")
  if [ "$script" == "bash" ] || [ "$script" == "" ]; then 
    #echo "$(basename "$0") Script is likely running from curl"
    # We don't actualy use this, but may in the future to leave it here
    FROM_CURL=$TRUE
  fi
fi

if [[ $EUID -ne 0 ]]; then
   logerr "This script must be run as root" 
   exit 1
fi

#if [ ! -t 0 ]; then
  #Don't use log function here as we will cleanout the file if it exists.
  # Can't use $0 below as this script might be piped into bash from curl
  echo "$SELF - $(date) " 2>/dev/null > "$OUTPUT"
#fi

if check_can_upgrade; then
  installed_version
  if [[ "$INSTALLED_VERSION" != "" ]]; then
    log "Current AqualinkD installation $INSTALLED_VERSION"
    log "System OK to upgrade AqualinkD to $REL_VERSION"
  else
    log "System OK to install AqualinkD $REL_VERSION"
  fi
  
  #exit $TRUE;
else
  logerr "Can not upgrade, Please fix error(s)!"
  exit $FALSE;
fi

case $1 in
  check|checkupgradable)
    # We have already done the check, and returned false at this point, so return true.
    exit $TRUE
  ;;
  development)
    if ! latest_development_version; then logerr "getting development version";exit "$FALSE"; fi
    if ! download_latest_development; then logerr "downloading latest development";exit "$FALSE"; fi
    run_install_script "$DEV_VERSION"
    cleanup
  ;;
  # Add Delete / remove / clean.
  clean|delete|remove)
    if ! remove_install; then logerr "Removing install";exit "$FALSE"; fi
    log "Removed install"
  ;;
  list|versions)
    get_all_versions
  ;;
  v*)
    if ! download_version $1; then logerr "downloading version $1";exit "$FALSE"; fi
    run_install_script "$REL_VERSION"
    cleanup
  ;;
  -h|help|h)
    echo "AqualinkD Installation script"
    echo "$SELF               <- download and install latest AqualinkD version"
    echo "$SELF latest        <- download and install latest AqualinkD version"
    echo "$SELF development   <- download and install latest AqualinkD development version"
    echo "$SELF clean         <- Remove AqualinkD"
    echo "$SELF list          <- List available versions to install"
    echo "$SELF v1.0.0        <- install AqualinkD v1.0.0 (use list option to see available versions)"
  ;;
  latest|*)
    if ! download_latest_release; then logerr "downloading latest"; exit "$FALSE"; fi
    run_install_script "$REL_VERSION"
    cleanup
  ;;
esac


exit


# List all versions
# curl -fsSL https://api.github.com/repos/sfeakes/aqualinkd/releases | awk 'match($0,/.*"html_url": "(.*\/releases\/tag\/.*)".*/)'
# curl -fsSL "https://api.github.com/repos/sfeakes/AqualinkD/releases" | awk 'match($0,/.*"tarball_url": "(.*\/tarball\/.*)".*/)' | awk -F '"' '{print $4}'