#!/bin/bash

set -o errexit
set -o nounset
set -o pipefail
set -o xtrace

# Modeled after ~/git/apache/fineract/.github/workflows/build-mariadb.yml and ~/git/apache/fineract/.github/workflows/build-postgresql.yml (these are very similar)

composeFilePath=$HOME/fineract-test-compose.yml

#export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
#export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
#export JAVA_HOME=/usr/lib/jvm/zulu17
#export JAVA_HOME=/usr/lib/jvm/zulu18
export JAVA_HOME=/usr/lib/jvm/zulu21
#export JAVA_HOME=/usr/lib/jvm/zulu22
#export JAVA_HOME=/usr/lib/jvm/zulu23
#export JAVA_HOME=/usr/lib/jvm/zulu24

# Incorrect default Java-related executables breaks tests.
# Something might be shelling out to the default of one of these, leading to
# cases where we're using versions of software from different JDKs.
# Latest I've seen is: java.lang.UnsupportedClassVersionError: sun/util/resources/cldr/provider/CLDRLocaleDataMetaInfo has been compiled by a more recent version of the Java Runtime (class file version 65.0), this version of the Java Runtime only recognizes class file versions up to 55.0
sudo update-alternatives --set java $JAVA_HOME/bin/java
sudo update-alternatives --set javac $JAVA_HOME/bin/javac
sudo update-alternatives --set javadoc $JAVA_HOME/bin/javadoc

gradleRun='gradle'         # idea: ./gradlew
gradleArgs='--no-continue' # idea: --daemon --info

# Ugh. This seems to be required for consistent test results.
TZ=Asia/Kolkata

dbType="$1"
if [[ $dbType == "mariadb" ]]
then
    dropArg=dropDB
    createArg=createDB
    dbTypeArg=''
elif [[ $dbType == "postgres" ]]
then
    dropArg=dropPGDB
    createArg=createPGDB
    dbTypeArg='-PdbType=postgresql'
else
    true '☠️  error, unknown db type. Must be mariadb or postgres.'
    exit 1
fi

storageArg="$2"
if [[ $storageArg == "normal_disk" ]]
then
    useRamdisk=no
elif [[ $storageArg == "ram_disk" ]]
then
    useRamdisk=yes
else
    true '☠️  error, unknown storage arg. Must be normal_disk or ram_disk.'
    exit 1
fi

function cleanUpAndDie() {
    true '💖 cleanUpAndDie: turn down stack'
    docker compose --file $composeFilePath down

    if [[ $useRamdisk == "yes" ]]
    then
        true '💖 cleanUpAndDie: destroy ramdisk'
        sudo umount "$HOME/.local/share/fineract/$dbType-ramdisk"
    fi

    $gradleRun --stop
    exit
}

trap cleanUpAndDie SIGINT

# FIXME - also change in $composeFilePath
if [[ $useRamdisk == "yes" ]]
then
    true '💖 set up ramdisk'
    if mount | grep -E '([p]ostgres|[m]ariadb)-ramdisk'
    then
        sudo umount "$HOME/.local/share/fineract/$dbType-ramdisk"
    fi
    sudo mount -t tmpfs -o size=512M,uid=1000,gid=1000,mode=0700 tmpfs "$HOME/.local/share/fineract/$dbType-ramdisk"
fi

true '💖 stack up: make sure db and mock-oauth2-server are running'
docker compose --file $composeFilePath down
docker compose --file $composeFilePath up --detach --wait "$dbType" mock-oauth2-server

if [[ $useRamdisk == "no" && $(find "$HOME/.local/share/fineract/$dbType-ramdisk/" -type f | wc -l) -ne 0 ]]
then
    true '☠️  error, ramdisk enabled in compose file? fix that first.'
    cleanUpAndDie
fi

true '💖 navigate to working copy, tidy up'
pushd ~/git/apache/fineract/

$JAVA_HOME/bin/java -version

# # 🤷 maybe this is Good?
# $gradleRun --stop || cleanUpAndDie

# # seems like a good idea -- shouldn't be necessary if I do the rest
# $gradleRun $gradleArgs clean || cleanUpAndDie

# 💣 STUFF TO MAKE VERY VERY CLEAN
# OMG stop all the caching everyone can't we just all get along
# # (FIXME - why does this sometimes fail? gradle Java VM from above still exiting after `gradle --stop`?)
# rm -rf ~/.gradle || cleanUpAndDie
# # maven detritus?
# rm -rf ~/.m2
# # not sure if this is necessary
# rm -rf /tmp/cargo*
# # 💥 get really really clean
# git clean -fdx

true '💖 purge and re-create databases'
$gradleRun $gradleArgs $dropArg -PdbName=fineract_default || true
$gradleRun $gradleArgs $dropArg -PdbName=fineract_tenants || true
$gradleRun $gradleArgs $createArg -PdbName=fineract_tenants || cleanUpAndDie
$gradleRun $gradleArgs $createArg -PdbName=fineract_default || cleanUpAndDie

# Build & Test
# (skip localstack setup, I guess we don't need a fineract-reports bucket)

true '💖 GBUILD'
if ! $gradleRun $gradleArgs build -x cucumber -x test -x doc
then
    true '☠️  error, build failed'
    cleanUpAndDie
fi

true '💖 GTEST CUCUMBER (optional)'
if ! $gradleRun $gradleArgs cucumber -x :fineract-e2e-tests-runner:cucumber
then
    true '☠️  error, cucumber failed'
    cleanUpAndDie
fi

fiveMinutes="$(( 60 * 5 ))"
startTime="$(date +%s)"

true '💖 GTEST MAIN/INTEGRATION (optional)'
# add --info and gradle will say what caching it is and isn't doing
if ! $gradleRun $gradleArgs test -x :twofactor-tests:test -x :oauth2-test:test :fineract-e2e-tests-runner:test $dbTypeArg
then
    true '☠️  error, integration tests failed'
    cleanUpAndDie
fi

endTime="$(date +%s)"

# FIXME - these cargo and "too quickly" sanity checks are (were?) necessary because sometimes Gradle was not actually trying to run them -- they serve no purpose now
# try `gradle --info` and watch to see if `:integration-tests:test` is cached
# try `gradle --rerun-tasks`
# see https://github.com/apache/fineract/pull/4612

# shellcheck disable=SC2009 # At this point we expect cargo to be running because it seems to hang around after integration tests. Maybe 45min of tests is too long and cargoStartLocal times out? or cargoStopLocal fails? also see note about Gradle caching above and on the mailing list
if ps auxwww | grep '[c]argo' > /dev/null
then
    # shellcheck disable=SC2009 # ignore pgrep suggestion
    ps auxwww | grep '[c]argo' | awk '{ print $2 }' | xargs -r kill
else
    true '🤔 cargo not running. Something is probably wrong.'
fi

# shellcheck disable=SC2004 # Ignore misrecognized quoting of start and end times
if [[ $(( $endTime - $startTime )) -lt $fiveMinutes ]];
then
    true '☠️  integration tests ended too quickly. Something is definitely wrong.'
    cleanUpAndDie
fi

true '💖 TEST 2FA'
if ! $gradleRun $gradleArgs :twofactor-tests:test $dbTypeArg
then
    true '☠️  error, 2FA tests failed'
    cleanUpAndDie
fi

true '💖 TEST OAUTH2'
if ! $gradleRun $gradleArgs :oauth2-tests:test $dbTypeArg
then
    true '☠️  error, oauth tests failed'
    cleanUpAndDie
fi

cleanUpAndDie
