#!/usr/bin/env bash

config()
{
  if [ "$(whoami)" = "root" ]
  then
    echo "It is not recommended to run this script as root. As a normal user, elevation will be prompted if needed."
    read -rp "Continue anyway? (Y/n) " confirm </dev/tty
    if [[ "$confirm" = "n" ]]; then exit 1; fi
  else
    if ! command -v sudo
    then
      echo "Please install and configure sudo before running this script."
      echo "sudo was not found, exiting..."
      exit 1
    elif ! groups | grep sudo; then
      echo "Please add your current user to the sudoers."
      echo "You can run the following as root: \"usermod -aG sudo $(whoami)\", then logout and login again"
      echo "sudo was not configured, exiting..."
      exit 1
    fi
    if ! groups | grep docker; then
      echo "Please add your current user to the docker group."
      echo "You can run the following as root: \"usermod -aG docker $(whoami)\", then logout and login again"
      echo "current user is not allowed to use docker, exiting..."
      exit 1
    fi
  fi
  if ! command -v awk || ! [[ $(awk -W version) =~ ^GNU ]]
  then
    echo "Please install GNU Awk before running this script."
    echo "gawk was not found, exiting..."
    exit 1
  fi
  FM_PATH=$(pwd)
  TYPE="NOT-FOUND"
  read -rp "Is Fab-manager installed at \"$FM_PATH\"? (y/N) " confirm </dev/tty
  if [ "$confirm" = "y" ]; then
    test_docker_compose
    if [[ "$TYPE" = "NOT-FOUND" ]]
    then
      echo "PostgreSQL was not found on the current system, exiting..."
      exit 2
    fi
  else
    echo "Please run this script from the Fab-manager's installation folder"
    exit 1
  fi
}

test_free_space()
{
  # checking disk space (minimum required = 1.2GB)
  required=$(du -d 0 "$PG_PATH" | awk '{ print $1 }')
  space=$(df "$FM_PATH" | awk '/[0-9]%/{print $(NF-2)}')
  if [ "$space" -lt "$required" ]
  then
    echo "Not enough free disk space to perform upgrade. Please free at least $required bytes of disk space and try again"
    df -h "$FM_PATH"
    exit 7
  fi
}

test_docker_compose()
{
  if [[ -f "$FM_PATH/docker-compose.yml" ]]
  then
    docker-compose ps | grep postgres
    if [[ $? = 0 ]]
    then
      TYPE="DOCKER-COMPOSE"
    fi
  fi
}

read_path()
{
    PG_PATH=$(awk "BEGIN { FS=\"\n\"; RS=\"\"; } { match(\$0, /image: postgres:$OLD(\n|.)+volumes:(\n|.)+(-.*postgresql\/data)/, lines); FS=\"[ :]+\"; RS=\"\r\n\"; split(lines[3], line); print line[2] }" "$FM_PATH/docker-compose.yml")
    PG_PATH="${PG_PATH/\$\{PWD\}/$FM_PATH}"
    PG_PATH="${PG_PATH/\./$FM_PATH}"
    PG_PATH="${PG_PATH/[[:space:]]/}"
}

prepare_path()
{
  if ! ls "$PG_PATH/base" 2>/dev/null
  then
    echo "PostgreSQL does not seems to be installed in $PG_PATH"
    read -rep "Please specify the PostgreSQL data folder: " PG_PATH </dev/tty
    prepare_path
  else
    NEW_PATH="$PG_PATH-$NEW"
    mkdir -p "$NEW_PATH"
  fi
}

docker_down()
{
  docker-compose down
  ensure_pg_down
}

ensure_pg_down()
{
  if [ -f "$PG_PATH/postmaster.pid" ]; then
    echo 'ERROR: lock file "postmaster.pid" exists'
    docker-compose ps | grep postgres
    if [[ $? = 1 ]]; then
      read -rp 'docker-compose container is not running. Confirm delete the lock file? (y/N) ' confirm </dev/tty
      if [ "$confirm" = "y" ]; then
        if [ "$(whoami)" = "root" ]; then COMMAND="rm"
        else COMMAND="sudo rm"; fi
        "$COMMAND" -f "$PG_PATH/postmaster.pid"
      fi
    else
      echo 'docker-compose container is still running, retrying to stop...'
      sleep 2
      docker_down
    fi
  fi
}

pg_upgrade()
{
  echo "docker run --rm  -v $PG_PATH:/var/lib/postgresql/$OLD/data -v $NEW_PATH:/var/lib/postgresql/$NEW/data tianon/postgres-upgrade:$OLD-to-$NEW"
  docker run --rm \
    -v "$PG_PATH:/var/lib/postgresql/$OLD/data" \
    -v "$NEW_PATH:/var/lib/postgresql/$NEW/data" \
    "tianon/postgres-upgrade:$OLD-to-$NEW"
}


upgrade_compose()
{
  echo -e "\nUpgrading docker-compose installation from $OLD to $NEW..."

  # update image tag and data directory into docker-compose file
  awk "BEGIN { FS=\"\n\"; RS=\"\"; } { print gensub(/(image: postgres:$OLD(\n|.)+volumes:(\n|.)+(-.*postgresql\/data))/, \"image: postgres:$NEW\n    volumes:\n      - ${NEW_PATH}:/var/lib/postgresql/data\", \"g\") }" "$FM_PATH/docker-compose.yml" > "$FM_PATH/.awktmpfile" && mv "$FM_PATH/.awktmpfile" "$FM_PATH/docker-compose.yml"
}

trust_pg_hba_conf()
{
  if [ "$(whoami)" = "root" ]; then COMMAND="tee"
  else COMMAND="sudo tee"; fi
  {
    echo
    echo "host all all all trust"
  } | "$COMMAND" -a "$NEW_PATH/pg_hba.conf" > /dev/null
}

docker_up()
{
  docker-compose pull
  docker-compose up -d
}

clean()
{
  read -rp "Remove the previous PostgreSQL data folder? (y/N) " confirm </dev/tty
  if [[ "$confirm" = "y" ]]; then
    read -rp "WARNING: This cannot be undone! If something went wrong during the upgrade, you'll lost all your data. Are you really sure? (y/N) " confirm </dev/tty
    if [[ "$confirm" = "y" ]]; then
      echo "Deleting $PG_PATH..."
      rm -rf "$PG_PATH"
    fi
  fi
}

function trap_ctrlc()
{
  echo "Ctrl^C, exiting..."
  exit 2
}

upgrade_postgres()
{
  config
  read -rp "Continue with upgrading? (y/N) " confirm </dev/tty
  if [[ "$confirm" = "y" ]]; then
    trap "trap_ctrlc" 2 # SIGINT
    OLD='9.4'
    NEW='9.6'
    read_path
    test_free_space
    prepare_path
    docker_down
    pg_upgrade
    upgrade_compose
    trust_pg_hba_conf
    docker_up
    clean
  fi
}

upgrade_postgres "$@"
