#!/bin/bash
# This file is in the public domain.

# shellcheck disable=SC2317
## Coloring style Text shell script
COLOR='\033[0;35m'
NOCOLOR='\033[0m'
BOLD="$(tput bold)"
NORM="$(tput sgr0)"

set -eu

# Replace with 0 for nexus...
USE_FAKEBANK=1
if [ 1 = "$USE_FAKEBANK" ]
then
    ACCOUNT="exchange-account-2"
    WIRE_METHOD="x-taler-bank"
    BANK_FLAGS="-f -d $WIRE_METHOD -u $ACCOUNT"
    BANK_URL="http://localhost:18082/"
    MERCHANT_PAYTO="payto://x-taler-bank/localhost/anastasis?receiver-name=anastasis"
else
    ACCOUNT="exchange-account-1"
    WIRE_METHOD="iban"
    BANK_FLAGS="-ns -d $WIRE_METHOD -u $ACCOUNT"
    BANK_URL="http://localhost:18082/"
    MERCHANT_PAYTO="payto://iban/SANDBOXX/DE648226?receiver-name=anastasis"
fi

# Check we can actually run
echo -n "Testing for jq"
jq -h > /dev/null || exit_skip "jq required"
echo " FOUND"
echo -n "Testing for anastasis-reducer ..."
anastasis-reducer -h > /dev/null || exit_skip "anastasis-reducer required"
echo " FOUND"

echo -n "Testing for taler"
taler-exchange-httpd -h > /dev/null || exit_skip " taler-exchange required"
taler-merchant-httpd -h > /dev/null || exit_skip " taler-merchant required"
echo " FOUND"

echo -n "Testing for taler-wallet-cli"
taler-wallet-cli -v >/dev/null </dev/null || exit_skip " MISSING"
echo " FOUND"

echo -n "Testing for anastasis-httpd"
anastasis-httpd -h >/dev/null </dev/null || exit_skip " MISSING"
echo " FOUND"

. setup.sh
# Launch exchange, merchant and bank.
# shellcheck disable=SC2086
setup -c "test_reducer.conf" \
      -emw \
      -r merchant-exchange-default \
      $BANK_FLAGS


# Cleanup to run whenever we exit
function cleanup()
{
    exit_cleanup
    for n in $(jobs -p)
    do
        kill "$n" 2> /dev/null || true
    done
    rm -rf "$CONF" "$WALLET_DB" "$TFILE" "$UFILE" "$TMP_DIR"
    wait
}

CONF_1="test_anastasis_reducer_1.conf"
CONF_2="test_anastasis_reducer_2.conf"
CONF_3="test_anastasis_reducer_3.conf"
CONF_4="test_anastasis_reducer_4.conf"

# Exchange configuration file will be edited, so we create one
# from the template.
CONF="test_reducer.conf.edited"

TMP_DIR=$(mktemp -p "${TMPDIR:-/tmp}" -d keys-tmp-XXXXXX)
WALLET_DB=$(mktemp -p "${TMPDIR:-/tmp}"  test_reducer_wallet.json-XXXXXX)
TFILE=$(mktemp -p "${TMPDIR:-/tmp}" test_reducer_statePPXXXXXX)
UFILE=$(mktemp -p "${TMPDIR:-/tmp}" test_reducer_stateBFXXXXXX)

# Install cleanup handler (except for kill -9)
trap cleanup EXIT


echo -n "Initialize anastasis databases ..."
# Name of the Postgres database we will use for the script.
# Will be dropped, do NOT use anything that might be used
# elsewhere
TARGET_DB_1=$(anastasis-config -c "$CONF_1" -s stasis-postgres -o CONFIG | sed -e "s/^postgres:\/\/\///")
TARGET_DB_2=$(anastasis-config -c "$CONF_2" -s stasis-postgres -o CONFIG | sed -e "s/^postgres:\/\/\///")
TARGET_DB_3=$(anastasis-config -c "$CONF_3" -s stasis-postgres -o CONFIG | sed -e "s/^postgres:\/\/\///")
TARGET_DB_4=$(anastasis-config -c "$CONF_4" -s stasis-postgres -o CONFIG | sed -e "s/^postgres:\/\/\///")

dropdb "$TARGET_DB_1" >/dev/null 2>/dev/null || true
createdb "$TARGET_DB_1" || exit_skip "Could not create database $TARGET_DB_1"
anastasis-dbinit -c "$CONF_1" 2> anastasis-dbinit_1.log
dropdb "$TARGET_DB_2" >/dev/null 2>/dev/null || true
createdb "$TARGET_DB_2" || exit_skip "Could not create database $TARGET_DB_2"
anastasis-dbinit -c "$CONF_2" 2> anastasis-dbinit_2.log
dropdb "$TARGET_DB_3" >/dev/null 2>/dev/null || true
createdb "$TARGET_DB_3" || exit_skip "Could not create database $TARGET_DB_3"
anastasis-dbinit -c "$CONF_3" 2> anastasis-dbinit_3.log
dropdb "$TARGET_DB_4" >/dev/null 2>/dev/null || true
createdb "$TARGET_DB_4" || exit_skip "Could not create database $TARGET_DB_4"
anastasis-dbinit -c "$CONF_4" 2> anastasis-dbinit_4.log

echo " OK"

echo -n "Launching anastasis services ..."
PREFIX="" #valgrind
$PREFIX anastasis-httpd -c $CONF_1 2> anastasis-httpd_1.log &
$PREFIX anastasis-httpd -c $CONF_2 2> anastasis-httpd_2.log &
$PREFIX anastasis-httpd -c $CONF_3 2> anastasis-httpd_3.log &
$PREFIX anastasis-httpd -c $CONF_4 2> anastasis-httpd_4.log &

echo -n "Waiting for anastasis services ..."
# Wait for anastasis services to be available
for n in $(seq 1 50)
do
    echo -n "."
    sleep 0.1
    OK=0
   # anastasis_01
    wget --tries=1 --timeout=1 http://localhost:8086/ -o /dev/null -O /dev/null >/dev/null || continue
    # anastasis_02
    wget --tries=1 --timeout=1 http://localhost:8087/ -o /dev/null -O /dev/null >/dev/null || continue
    # anastasis_03
    wget --tries=1 --timeout=1 http://localhost:8088/ -o /dev/null -O /dev/null >/dev/null || continue
    # anastasis_04
    wget --tries=1 --timeout=1 http://localhost:8089/ -o /dev/null -O /dev/null >/dev/null || continue
    OK=1
    break
done

if [ 1 != "$OK" ]
then
    exit_skip "Failed to launch anastasis services"
fi
echo "OK"

echo -n "Configuring merchant instance ..."
# Setup merchant

curl -H "Content-Type: application/json" -X POST -d '{"auth":{"method":"external"},"id":"admin","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' http://localhost:9966/management/instances


curl -H "Content-Type: application/json" -X POST -d '{"payto_uri":"'"$MERCHANT_PAYTO"'"}' http://localhost:9966/private/accounts



echo " DONE"

echo -en "${COLOR}${BOLD}Test enter secret in a backup state ...${NORM}${NOCOLOR}"

$PREFIX anastasis-reducer -a \
  '{"secret": { "value" : "veryhardtoguesssecret", "mime" : "text/plain" } }' \
  enter_secret resources/06-backup.json "$TFILE"

STATE=$(jq -r -e .backup_state < "$TFILE")
if [ "$STATE" != "SECRET_EDITING" ]
then
    jq -e . "$TFILE"
    exit_fail "Expected new state to be 'SECRET_EDITING', got '$STATE'"
fi

echo " DONE"
echo -en "${COLOR}${BOLD}Test expiration change ...${NORM}${NOCOLOR}"

SECS=$(date '+%s')
# Use 156 days into the future to get 1 year
SECS=$(( SECS + 13478400 ))

$PREFIX anastasis-reducer -a \
  "$(jq -n '
   {"expiration": { "t_s" : $SEC } }' \
   --argjson SEC "$SECS"
  )" \
  update_expiration "$TFILE" "$UFILE"

STATE=$(jq -r -e .backup_state < "$UFILE")
if test "$STATE" != "SECRET_EDITING"
then
    jq -e . "$UFILE"
    exit_fail "Expected new state to be 'SECRET_EDITING', got '$STATE'"
fi

FEES=$(jq -r -e '.upload_fees[0].fee' < "$UFILE")
# 4x 4.99 for the annual fee of each of the four providers in the state,
# plus 3x0.01 for the truth uploads: 06-backup.json has three authentication
# methods and the reducer places each of them at a provider of its own.
if [ "$FEES" != "TESTKUDOS:19.99" ]
then
    jq -e . "$UFILE"
    exit_fail "Expected upload fees to be 'TESTKUDOS:19.99', got '$FEES'"
fi


echo " DONE"
echo -en "${COLOR}${BOLD}Test advance to payment ...${NORM}${NOCOLOR}"

$PREFIX anastasis-reducer next "$UFILE" "$TFILE"

STATE=$(jq -r -e .backup_state < "$TFILE")
if [ "$STATE" != "TRUTHS_PAYING" ]
then
    jq -e . "$TFILE"
    exit_fail "Expected new state to be 'TRUTHS_PAYING', got '$STATE'"
fi

# FIXME: this test is specific to how the
# C reducer stores state (redundantly!), should converge eventually!

#TMETHOD=$(jq -r -e '.policies[0].methods[0].truth.type' < $TFILE)
#if test $TMETHOD != "question"
#then
#    exit_fail "Expected method to be >='question', got $TMETHOD"
#fi
#
#echo " OK"


#Pay

echo -en "${COLOR}${BOLD}Withdrawing amount to wallet ...${NORM}${NOCOLOR}"

EXCHANGE_URL="$(taler-exchange-config -c "$CONF" -s exchange -o BASE_URL)"

rm "$WALLET_DB"
taler-wallet-cli \
    --no-throttle \
    --wallet-db="$WALLET_DB" \
    api \
    --expect-success 'withdrawTestBalance' \
  "$(jq -n '
    {
        amount: "TESTKUDOS:40",
        corebankApiBaseUrl: $BANK_URL,
        exchangeBaseUrl: $EXCHANGE_URL
    }' \
    --arg BANK_URL "${BANK_URL}" \
    --arg EXCHANGE_URL "${EXCHANGE_URL}"
  )" 2>wallet-withdraw.err \
      >wallet-withdraw.log
taler-wallet-cli \
    --no-throttle \
    --wallet-db="$WALLET_DB" \
    run-until-done \
    2>wallet-withdraw-finish.err \
    >wallet-withdraw-finish.log

echo " OK"

echo -en "${COLOR}${BOLD}Making payments for truth uploads ... ${NORM}${NOCOLOR}"
OBJECT_SIZE=$(jq -r -e '.payments | length' < "$TFILE")
for ((INDEX=0; INDEX < "$OBJECT_SIZE"; INDEX++))
do
    PAY_URI=$(jq --argjson INDEX $INDEX -r -e '.payments[$INDEX]' < "$TFILE")
    # run wallet CLI
    echo -n "$INDEX"
    taler-wallet-cli \
        --no-throttle \
        --wallet-db="$WALLET_DB" \
        handle-uri "${PAY_URI}" \
        -y \
        2>wallet-pay1.err \
        >wallet-pay1.log
    echo -n ","
done
echo " OK"
echo -e "${COLOR}${BOLD}Running wallet run-until-done...${NORM}${NOCOLOR}"
taler-wallet-cli \
    --wallet-db="$WALLET_DB" \
    run-until-done \
    2>wallet-pay-finish.err \
    >wallet-pay-finish.log
echo -e "${COLOR}${BOLD}Payments done${NORM}${NOCOLOR}"


echo -en "${COLOR}${BOLD}Try to upload again ...${NORM}${NOCOLOR}"
$PREFIX anastasis-reducer pay "$TFILE" "$UFILE"
mv "$UFILE" "$TFILE"
echo " OK"


STATE="$(jq -r -e .backup_state < "$TFILE")"
if [ "$STATE" != "POLICIES_PAYING" ]
then
    exit_fail "Expected new state to be 'POLICIES_PAYING', got '$STATE'"
fi

echo -en "${COLOR}${BOLD}Making payments for policy uploads ... ${NORM}${NOCOLOR}"
OBJECT_SIZE="$(jq -r -e '.policy_payment_requests | length' < "$TFILE")"
for ((INDEX=0; INDEX < "$OBJECT_SIZE"; INDEX++))
do
    PAY_URI="$(jq --argjson INDEX "$INDEX" -r -e '.policy_payment_requests[$INDEX].payto' < "$TFILE")"
    # run wallet CLI
    export PAY_URI
    echo -n "$INDEX"
    taler-wallet-cli \
        --wallet-db="$WALLET_DB" \
        handle-uri "$PAY_URI" \
        -y \
        2>"wallet-pay2-$INDEX.err" \
        >"wallet-pay2-$INDEX.log"
    echo -n ","
done
echo " OK"
echo -e "${COLOR}${BOLD}Running wallet run-until-done...${NORM}${NOCOLOR}"
taler-wallet-cli \
    --wallet-db="$WALLET_DB" \
    run-until-done \
    2>wallet-pay2-finish.err \
    >wallet-pay2-finish.log
echo -e "${COLOR}${BOLD}Payments done${NORM}${NOCOLOR}"

echo -en "${COLOR}${BOLD}Try to upload again ...${NORM}${NOCOLOR}"
$PREFIX anastasis-reducer pay "$TFILE" "$UFILE"

echo " OK"

echo -n "Final checks ..."

STATE=$(jq -r -e .backup_state < "$UFILE")
if [ "$STATE" != "BACKUP_FINISHED" ]
then
    exit_fail "Expected new state to be BACKUP_FINISHED, got $STATE"
fi

jq -r -e .core_secret \
   < "$UFILE" \
   > /dev/null \
    && exit_fail "'core_secret' was not cleared upon success"

echo " OK"
exit 0
