#!/usr/bin/env bash

# More details: https://kitten.small-web.org/reference/technical-manual/#launcher

set -e

# Path usage adheres to freedesktop.org XDG Base Directory Specification
# https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
# HOME is unset under some systemd units and in some containers.
: "${HOME:=$(eval echo "~$(id -un)")}"
case "${XDG_DATA_HOME:-}" in
  /*) DATA_HOME="$XDG_DATA_HOME" ;;
  *)  DATA_HOME="$HOME/.local/share" ;;
esac
SMALL_TECH_DATA_HOME="${DATA_HOME}/small-tech.org"
KITTEN_DATA_HOME="${SMALL_TECH_DATA_HOME}/kitten"
KITTEN_RUNTIMES_DIRECTORY="${KITTEN_DATA_HOME}/runtimes"

# Save the base path so we can pass it to Kitten so it can calculate the
# absolute path of the path to serve even if a relative path is given from
# the current working directory.
workingDirectory=$(pwd)

# Run Kitten from Kitten distribution folder not folder kitten command
# was run from.
pushd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" > /dev/null

KITTEN_RUNTIME="${KITTEN_RUNTIMES_DIRECTORY}/$(cat ./node-version 2>/dev/null || true)/bin/node"
[ -x "${KITTEN_RUNTIME}" ] || { echo "❌ Kitten’s runtime is missing at ${KITTEN_RUNTIME}. Run the Kitten installer again." >&2; exit 1; }

# Only PRODUCTION=true runs Kitten in production.
[[ "${PRODUCTION}" == 'true' ]] || unset PRODUCTION

# The update guard exits with 3 when it has pointed app at another version, whose launcher then runs.
if [[ "${PRODUCTION}" == 'true' && -e "${KITTEN_DATA_HOME}/updates/pending" ]]; then
  guardStatus=0
  "${KITTEN_RUNTIME}" ./update-guard.js start || guardStatus=$?
  if [ "${guardStatus}" -eq 3 ]; then
    popd > /dev/null
    exec "${KITTEN_DATA_HOME}/app/kitten" "$@"
  fi
  [ "${guardStatus}" -eq 0 ] || exit "${guardStatus}"
fi

# Run either the kitten bundle directly (in production), or run the
# kitten-process-manager (in development) which will restart Kitten
# in place of systemd.
# Note that the 0x flame graph module does not work with node cluster
# and thus cannot be used in development mode (we use node cluster to
# implement the development-time process manager).
mainProcess='./kitten-process-manager.js'

# If the person wants to run a command other than serve during
# development, we load the main bundle directly. Given that the
# serve command is the default and any path could be supplied
# as the first argument, we have to manually check for all supported
# commands. This introduces a bit of redundancy and maintenance headache
# by replicating the command names from cli/index.js but it is,
# currently, the best we can do. Just remember you have to update
# the commmand names in two places when you add a new command. 
if [[ "${PRODUCTION}" == 'true' || "${FLAME_GRAPH}" == 'true'
      || "$1" == 'run' || "$1" == 'db' || "$1" == '_db'
      || "$1" == 'deploy' || "$1" == 'status' || "$1" == 'logs' || "$1" == 'start'
      || "$1" == 'stop' || "$1" == 'restart' || "$1" == 'enable' || "$1" == 'disable'
      || "$1" == 'update' || "$1" == 'uninstall' || "$1" == 'version' || "$1" == 'help'
      || "$1" == '--version' || "$1" == '--help'
   ]]; then
  mainProcess='./kitten-bundle.js'
fi

# If flame graph is requested, generate it using 0x and
# have it open up in a web browser.
flameGraph=''
if [[ "${FLAME_GRAPH}" == 'true' ]]; then
  kitten-npm install -g 0x # 0x must be globally installed for this to work.
  flameGraph='0x -o --'
fi

# If the debugger is requested (INSPECT=true), run
# Node using the --inspect flag and run the bundle directly.
inspect=''
# shellcheck disable=SC2153
if [[ "${INSPECT}" == 'true' ]]; then
  inspect='--inspect-brk'
  mainProcess='./kitten-bundle.js'
fi

# In development, the process manager replaces this launcher.
if [[ "${mainProcess}" == './kitten-process-manager.js' ]]; then
  launch='exec'
else
  launch=''
fi

# Launch Node.
QUIET=true \
$launch \
$flameGraph \
"$KITTEN_RUNTIME" \
$inspect \
--enable-source-maps \
--import ./loader-bundle.js \
"${mainProcess}" \
--working-directory="${workingDirectory}" \
"$@"

# Return to folder Kitten was evoked from when execution ends.
trap 'popd > /dev/null' EXIT
