#!/bin/bash

function realpath {
  echo "$(cd "$(dirname "$1")"; pwd)"/"$(basename "$1")";
}

#---------------------------------------------------------------------------------------------------
function show_help {
  echo
  echo "Usage: $0 [OPTIONS] [COMPONENT|PROCESS]"
  echo
  echo "Where COMPONENT is the name of the App Search stack component you want to run:"
  echo "  all     - All components (default)"
  echo "  app     - HTTP API and the web application"
  echo "  worker  - Asynchronous workers (indexing, document creation, etc)"
  echo
  echo "When running in single-process mode, the following PROCESS values are supported:"
  echo "  app-server - HTTP API and the web application server only (needs filebeat deployed separately)"
  echo "  worker     - A pool of asynchronous workers"
  echo "  filebeat   - A filebeat instance used to index analytics and request logs into Elasticsearch"
  echo
  echo "Supported options:"
  echo "  --help              - Useful information on how to run this script"
  echo "  --process           - Runs the system in a single-process mode allowing for scaling components separately"
  echo "  --diagnostic-report - Generates a compressed, diagnostic log output for troubleshooting purposes."
  echo "  --reset-auth        - For standard authentication source: Resets login and password."
  echo "                        For elasticsearch-native and elasticsearch-saml authentication sources:"
  echo "                        Removes the current role mappings. All users will be granted the owner role."
  echo
}

if [ "$1" == '-h' ] || [ "$1" == '--help' ]; then
  show_help
  exit 0
fi

#---------------------------------------------------------------------------------------------------
set -eu

unset BUNDLE_APP_CONFIG
unset BUNDLE_BIN_PATH
unset BUNDLE_GEMFILE
unset BUNDLE_PATH
unset BUNDLER_VERSION
unset GEM_HOME
unset GEM_PATH
unset RUBYLIB
unset RUBYOPT

BIN_DIR=$(dirname "$0")
BIN_DIR=$(realpath "$BIN_DIR")
export APP_ROOT="$(cd "$BIN_DIR/.."; pwd)"

CONFIG_DIR="$APP_ROOT/config"
LIB_DIR="$APP_ROOT/lib"

# Need this for Filebeat config
export RAILS_ENV=loco_togo_production

# Need this because warbler uses the default one for some reason
export BUNDLE_GEMFILE=Gemfile-LocoTogo

# War file containing all of our code
export WAR_FILE="$APP_ROOT/lib/app-search.war"

# Detect the platform
PLATFORM=$(uname -s | awk '{print tolower($0)}')
ARCH=$(uname -m)
PLATFORM_FULL="$PLATFORM-$ARCH"

# Make sure the platform is supported
if [ "$PLATFORM_FULL" != "linux-x86_64" ] && [ "$PLATFORM_FULL" != "darwin-x86_64" ]; then
  echo
  echo "Elastic App Search currently only supports OSX and Linux operating systems on 64-bit platforms."
  echo
  exit 1
fi

# Filebeat locations
export FILEBEAT_BIN="$BIN_DIR/vendor/filebeat/filebeat-$PLATFORM_FULL"
export FILEBEAT_DIR="$APP_ROOT/filebeat"

# Forego (process manager) and entrypoints location
export ENTRYPOINTS_DIR="$LIB_DIR/entrypoints"
export FOREGO_BIN="$BIN_DIR/vendor/forego/forego-$PLATFORM_FULL"

#---------------------------------------------------------------------------------------------------
source "$LIB_DIR/require_java_version.sh"

# Load common environment settings
source "$CONFIG_DIR/env.sh"

REQUIRED_JAVA_OPTS="-Djruby.cli.warning.level=NIL -Dwarbler.debug=true -Djava.awt.headless=true"

export APP_SERVER_JAVA_OPTS="$APP_SERVER_JAVA_OPTS $REQUIRED_JAVA_OPTS"
export FILEBEAT_JAVA_OPTS="$FILEBEAT_JAVA_OPTS $REQUIRED_JAVA_OPTS"
export WORKER_JAVA_OPTS="$WORKER_JAVA_OPTS $REQUIRED_JAVA_OPTS"

#---------------------------------------------------------------------------------------------------
# Prepare config file
#---------------------------------------------------------------------------------------------------
if [[ -z "${APP_SEARCH_CONFIG_PATH:-}" ]]; then
  export APP_SEARCH_CONFIG_PATH="$CONFIG_DIR/app-search.yml"
fi

if [[ "$APP_SEARCH_CONFIG_PATH" != /* ]]; then
  export APP_SEARCH_CONFIG_PATH="$APP_ROOT/$APP_SEARCH_CONFIG_PATH"
fi

if [[ ! -a "$APP_SEARCH_CONFIG_PATH" ]]; then
  echo "Cannot read APP_SEARCH_CONFIG_PATH file because it does not exist, it's currently $APP_SEARCH_CONFIG_PATH"
  echo
  exit 1
fi

if [[ ! -r "$APP_SEARCH_CONFIG_PATH" ]]; then
  echo "Cannot read APP_SEARCH_CONFIG_PATH file, it's currently $APP_SEARCH_CONFIG_PATH"
  echo
  exit 1
fi

# Detect which components we are going to run, default to all
COMPONENT=${1:-all}
echo

#---------------------------------------------------------------------------------------------------
# Handle special commands
if [ "$COMPONENT" == "--reset-install-lock" ] || \
   [ "$COMPONENT" == "--reset-auth" ] || \
   [ "$COMPONENT" == "--diagnostic-report" ]; then
  APP_SEARCH_PROCESS=script exec "$_JAVA" -jar "$WAR_FILE" -S rails runner "LocoTogo.run_script!('$COMPONENT')"
  exit 0
fi

#---------------------------------------------------------------------------------------------------
# Single-process mode
#---------------------------------------------------------------------------------------------------
if [ "$COMPONENT" == "--process" ]; then
  PROCESS_NAME=${2:-}
  if [ "$PROCESS_NAME" == "" ]; then
    echo "ERROR: Please provide a process name to run!"
    show_help
    exit 1
  fi

  if [ "$PROCESS_NAME" != 'app-server' ] && [ "$PROCESS_NAME" != 'worker' ] && [ "$PROCESS_NAME" != 'filebeat' ]; then
    echo "ERROR: Invalid process name '$PROCESS_NAME'!"
    show_help
    exit 1
  fi

  ENTRYPOINT_FILE="${ENTRYPOINTS_DIR}/${PROCESS_NAME}.sh"
  if [ ! -f "$ENTRYPOINT_FILE" ]; then
    echo "ERROR: Could not find an entrypoint file for process '$PROCESS_NAME': ${ENTRYPOINT_FILE}"
    exit 1
  fi

  echo "Running Elastic App Search in a single-process mode (process = $PROCESS_NAME)!"
  echo
  echo "WARNING: Failure to run all of the components of Elastic App Search will result in a broken service!"
  echo "         This is an unsupported mode! The single-process mode should only be used in advanced"
  echo "         situations when all of App Search components are deployed and scaled separately."
  echo

  exec bash "$ENTRYPOINT_FILE"
fi

#---------------------------------------------------------------------------------------------------
# Components-based mode
#---------------------------------------------------------------------------------------------------
if [ "$COMPONENT" != 'all' ] && [ "$COMPONENT" != 'app' ] && [ "$COMPONENT" != 'worker' ]; then
  echo "ERROR: Invalid option or a component name '$COMPONENT'!"
  show_help
  exit 1
fi

echo "App Search is starting. It will take a few moments. App Search includes the following stack components:"
CONCURRENCY="all=0"

if [ "$COMPONENT" == 'all' ] || [ "$COMPONENT" == 'app' ]; then
  echo "  - An application server"
  CONCURRENCY="$CONCURRENCY,app-server=1"
fi

if [ "$COMPONENT" == 'all' ] || [ "$COMPONENT" == 'worker' ]; then
  echo "  - A pool of background workers"
  CONCURRENCY="$CONCURRENCY,worker=1"
fi

echo "  - A filebeat instance for indexing logs"
CONCURRENCY="$CONCURRENCY,filebeat=1"

echo
exec "$FOREGO_BIN" start -f "$LIB_DIR/Procfile" -c "$CONCURRENCY" -t "$SHUTDOWN_GRACE_TIME"
