#!/usr/bin/env bash

set -e

readonly script_name="./$(basename "$0")"

function print_help() {
  echo "Usage:"
  echo "  $script_name [OSM_FILE_NAME COUNTRY_CODE_LIST OSM_FILE_DOWNLOAD_URL]"
  echo "  $script_name --air"
  echo "  $script_name --help"
  echo
  echo "First form configures the back end to use GraphHopper routing mode and downloads an OSM data file during startup. \
Note that download and processing of the OSM file can take some time depending on its size. \
During this period, the application informs about back end service being unreachable."
  echo
  echo "Second form configures back end to use air routing mode. This is useful for development, debugging and \
hacking. Air distance routing is only an approximation. It is not useful for real vehicle routing."
  echo
  echo
  echo "OSM_FILE_NAME"
  echo "  The file downloaded from OSM_FILE_DOWNLOAD_URL will be saved under this name."
  echo
  echo "COUNTRY_CODE_LIST"
  echo "  ISO_3166-1 country code used to filter geosearch results. You can provide multiple, comma-separated values."
  echo
  echo "OSM_FILE_DOWNLOAD_URL"
  echo "  Should point to an OSM data file in PBF format accessible from OpenShift. The file will be downloaded \
during back end startup and saved as /deployments/local/OSM_FILE_NAME."
  echo
  echo
  echo "Example 1"
  echo "  $script_name belgium-latest.osm.pbf BE https://download.geofabrik.de/europe/belgium-latest.osm.pbf"
  echo
  echo "  Configures the application to filter geosearch results to Belgium and download the latest Belgium \
OSM extract from Geofabrik."
  echo
  echo
  echo "Example 2"
  echo "  $script_name my-city.osm.pbf FR https://download.bbbike.org/osm/extract/planet_12.032,53.0171_12.1024,53.0491.osm.pbf"
  echo
  echo "  Configures the application to download a custom region defined using the BBBike service and save it \
as my-city.osm.pbf."
}

function wrong_args() {
    print_help
    echo >&2
    echo >&2 "ERROR: Wrong arguments."
    exit 1
}

[[ $1 == "--help" ]] && print_help && exit 0

# Process arguments
declare -a dc_backend_env
case $# in
  0)
    print_help
    exit 0
    ;;
  1)
    if [[ $1 == --air ]]
    then
      dc_backend_env+=("APP_ROUTING_ENGINE=AIR")
      summary="No routing config provided. The back end will start in air distance mode.\n\n\
WARNING: Air distance mode does not give accurate values. \
It is only useful for evaluation, debugging, or incremental setup purpose. \
You can run '$script_name --help' to see other options."
    else
      wrong_args
    fi
    ;;
  2)
    dc_backend_env+=("APP_ROUTING_ENGINE=AIR")
    dc_backend_env+=("APP_ROUTING_OSM_FILE=$1")
    dc_backend_env+=("APP_REGION_COUNTRY_CODES=$2")
    summary="The back end will start in air mode. Use the back end pod to upload a graph directory or an OSM file. \
Then change routing mode to graphhopper. Run '$script_name --help' for more info."
    ;;
  3)
    dc_backend_env+=("APP_ROUTING_ENGINE=GRAPHHOPPER")
    dc_backend_env+=("APP_ROUTING_OSM_FILE=$1")
    dc_backend_env+=("APP_REGION_COUNTRY_CODES=$2")
    dc_backend_env+=("APP_ROUTING_OSM_DOWNLOAD_URL=$3")
    summary="The back end will download an OSM file on startup. \
It may take several minutes to download and process the file before the application is fully available!"
    download=1
    ;;
  *)
    wrong_args
esac

# Change dir to the project root (where the script is located) to correctly resolve module paths.
# This is needed in case the script was called from a different location than the project root.
cd -P "$(cd "$(dirname "${BASH_SOURCE[0]}")" &> /dev/null && pwd)"

readonly dir_backend=optaweb-vehicle-routing-backend
readonly dir_frontend=optaweb-vehicle-routing-frontend

# Fail fast if the project hasn't been built
if ! stat -t ${dir_backend}/target/*.jar > /dev/null 2>&1
then
  echo >&2 "ERROR: The back end module is not built! Build the project before running this script."
  exit 1
fi
if [[ ! -d ${dir_frontend}/docker/build ]]
then
  echo >&2 "ERROR: The front end module is not built! Build the project before running this script."
  exit 1
fi

command -v oc > /dev/null 2>&1 || {
  echo >&2 "ERROR: The oc client tool needs to be installed to connect to OpenShift."
  exit 1
}

[[ -x $(command -v oc) ]] || {
  echo >&2 "ERROR: The oc client tool is not executable. Please make it executable by running \
'chmod u+x \$(command -v oc)'."
  exit 1
}

# Print info about the current user and project
echo "Current user: $(oc whoami)"
# Check that the current user has at least one project
[[ -z "$(oc projects -q)" ]] && {
  echo >&2 "You have no projects. Use 'oc new-project <project-name>' to create one."
  exit 1
}
# Display info about the current project
oc project

# Check that the current project is empty
get_all=$(oc get all -o name)
if [[ -z "$get_all" ]]
then
  echo "The project appears to be empty."
else
  echo >&2
  echo >&2 "Project content:"
  echo >&2
  echo >&2 "$get_all"
  echo >&2
  echo >&2 "ERROR: The project is not empty."
  exit 1
fi

echo
echo -e "$summary"
echo

declare answer_continue
read -r -p "Do you want to continue? [y/N]: " "answer_continue"
[[ "$answer_continue" == "y" ]] || {
  echo "Aborted."
  exit 0
}

# Set up PostgreSQL
oc new-app --name postgresql postgresql-persistent

# Back end
# -- binary build (upload local artifacts + Dockerfile)
oc new-build --name backend --strategy=docker --binary --build-arg QUARKUS_APP_BUILD_QUALIFIER=postgresql
oc patch bc backend -p '{"spec":{"strategy":{"dockerStrategy":{"dockerfilePath":"src/main/docker/Dockerfile.jvm"}}}}'
oc start-build backend --from-dir=${dir_backend} --follow
# -- new app
oc new-app backend
# -- use PostgreSQL secret
oc set env deployment/backend --from=secret/postgresql
# -- set the rest of the configuration
oc set env deployment/backend "${dc_backend_env[@]}"
# Add a PersistentVolumeClaim
oc set volumes deployment/backend --add \
    --type pvc \
    --claim-size 1Gi \
    --claim-mode ReadWriteOnce \
    --name data-local \
    --mount-path /deployments/local

# Front end
# -- binary build
oc new-build --name frontend --strategy=docker --binary
oc start-build frontend --from-dir=${dir_frontend}/docker --follow
# -- new app
oc new-app frontend
# -- expose the service
oc expose svc/frontend
# -- change target port to 8080
oc patch route frontend -p '{"spec":{"port":{"targetPort":"8080-tcp"}}}'

echo
echo "You can access the application at http://$(oc get route frontend -o custom-columns=:spec.host | tr -d '\n') \
once the deployment is done."
if [[ -v download ]]
then
  echo
  echo "The OSM file download and its processing can take some time depending on its size. \
For large files (hundreds of MB) this can be several minutes. \
During this period, the application informs about the back end service being unreachable."
fi
