#!/bin/bash
# This file is part of TALER
# Copyright (C) 2014-2023 Taler Systems SA
#
# TALER is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 3, or
# (at your option) any later version.
#
# TALER is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public
# License along with TALER; see the file COPYING.  If not, see
# <http://www.gnu.org/licenses/>
#
# Testcase for #6363 (WiP)
set -eu

# Exit, with status code "skip" (no 'real' failure)
function exit_skip() {
    echo $1
    exit 77
}

echo -n "Testing for taler-harness"
taler-harness --help >/dev/null </dev/null || exit_skip " MISSING"
echo " FOUND"


# 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:8082/"
else
    echo -n "Testing for libeufin-bank"
    libeufin-bank --help >/dev/null </dev/null || exit_skip " MISSING"
    echo " FOUND"

    ACCOUNT="exchange-account-1"
    WIRE_METHOD="iban"
    BANK_FLAGS="-n -d $WIRE_METHOD -u $ACCOUNT"
    BANK_URL="http://localhost:18082/"
fi

. setup.sh
# Launch exchange, merchant and bank.
setup -c "test_template.conf" \
      -em \
      -r "merchant-exchange-default" \
      $BANK_FLAGS
LAST_RESPONSE=$(mktemp -p "${TMPDIR:-/tmp}" test_response.conf-XXXXXX)
CONF="test_template.conf.edited"
WALLET_DB=$(mktemp -p "${TMPDIR:-/tmp}" test_wallet.json-XXXXXX)
EXCHANGE_URL="http://localhost:8081/"


if [ 1 = "$USE_FAKEBANK" ]
then
    FACADE_URL="http://localhost:8082/accounts/gnunet/taler-revenue/"
    FACADE_USERNAME="gnunet"
    FACADE_PASSWORD="password"
else
    echo "not implemented for current libeufin-bank"
    exit 1
    export LIBEUFIN_SANDBOX_DB_CONNECTION='postgresql:///talercheck'
    export LIBEUFIN_SANDBOX_ADMIN_PASSWORD="secret"
    export LIBEUFIN_SANDBOX_URL="http://localhost:18082/"

    export EBICS_HOST="talerebics"
    export LIBEUFIN_SANDBOX_USERNAME="admin"
    export LIBEUFIN_SANDBOX_PASSWORD="secret"
    export EBICS_USER_ID="gnunet_ebics"
    export EBICS_PARTNER="GnunetPartner"
    export BANK_CONNECTION_NAME="gnunet-connection"
    export NEXUS_ACCOUNT_NAME="GnunetCredit"
    # The 'gnunet' account is created by
    # taler-bank-manage-testing and used for
    # the 'admin' instance, so this must be used here.
    export SANDBOX_ACCOUNT_NAME="gnunet"

    export LIBEUFIN_NEXUS_URL="http://localhost:8082"
    # These two are from taler-bank-manage-testing...

    # Define credentials for wirewatch user, will be Merchant client.
    CREDIT_USERNAME="merchant-wirewatch"
    CREDIT_PASSWORD="merchant-wirewatch-password"

    echo -n "Create credit user (for gnunet-merchant) at Nexus ..."

    export LIBEUFIN_NEXUS_DB_CONNECTION='postgresql:///talercheck'
    libeufin-nexus \
        superuser "$CREDIT_USERNAME" \
        --password="$CREDIT_PASSWORD" \
        &> nexus-credit-create.log
    echo " OK"
    export LIBEUFIN_NEXUS_USERNAME="$CREDIT_USERNAME"
    export LIBEUFIN_NEXUS_PASSWORD="$CREDIT_PASSWORD"
    export GNUNET_CREDIT_FACADE=facade-gnunet-credit

    libeufin-cli sandbox \
                 demobank \
                 new-ebicssubscriber \
                 --host-id ${EBICS_HOST} \
                 --user-id ${NEXUS_ACCOUNT_NAME} \
                 --partner-id ${EBICS_PARTNER} \
                 --bank-account ${SANDBOX_ACCOUNT_NAME} \
        &> sandbox-subscriber-create.log

    libeufin-cli \
        connections \
        new-ebics-connection \
        --ebics-url="${LIBEUFIN_SANDBOX_URL}ebicsweb" \
        --host-id=${EBICS_HOST} \
        --partner-id=${EBICS_PARTNER} \
        --ebics-user-id=${NEXUS_ACCOUNT_NAME} \
        ${BANK_CONNECTION_NAME} \
        &> nexus-connection-create.log

    libeufin-cli \
        connections \
        connect \
        ${BANK_CONNECTION_NAME} \
        &> nexus-connection-connect.log

    libeufin-cli \
        connections \
        download-bank-accounts \
        ${BANK_CONNECTION_NAME} \
        &> nexus-account-download.log

    libeufin-cli \
        connections \
        import-bank-account \
        --offered-account-id=${SANDBOX_ACCOUNT_NAME} \
        --nexus-bank-account-id=${NEXUS_ACCOUNT_NAME} \
        ${BANK_CONNECTION_NAME} \
        &> nexus-account-import.log

    libeufin-cli \
        facades \
        new-anastasis-facade \
        --currency=TESTKUDOS \
        --facade-name=${GNUNET_CREDIT_FACADE} \
        ${BANK_CONNECTION_NAME} \
        ${NEXUS_ACCOUNT_NAME} \
        &> nexus-new-facade.log

    FACADE_URL="http://localhost:18082/accounts/admin/taler-revenue/"
    # WAS: $(libeufin-cli facades list | jq .facades[0].baseUrl | tr -d \")

    # FIXME: is this correct? Strange to use the super-user
    # credentials here!
    FACADE_USERNAME="${CREDIT_USERNAME}"
    FACADE_PASSWORD="${CREDIT_PASSWORD}"
fi

echo -n "First prepare wallet with coins..."
rm -f "${WALLET_DB}"
taler-wallet-cli \
    --no-throttle \
    --wallet-db="$WALLET_DB" \
    api \
    --expect-success 'withdrawTestBalance' \
  "$(jq -n '
    {
        amount: "TESTKUDOS:99",
        corebankApiBaseUrl: $BANK_URL,
        exchangeBaseUrl: $EXCHANGE_URL
    }' \
    --arg BANK_URL "$BANK_URL" \
    --arg EXCHANGE_URL "$EXCHANGE_URL"
  )" 2>wallet-withdraw-1.err >wallet-withdraw-1.out
echo -n "."
if [ 1 = "$USE_FAKEBANK" ]
then
    # Fakebank is instant...
    sleep 0
else
    sleep 10
    # NOTE: once libeufin can do long-polling, we should
    # be able to reduce the delay here and run wirewatch
    # always in the background via setup
fi
echo -n "."
taler-exchange-wirewatch \
    -L "INFO" \
    -c "$CONF" \
    -t \
    &> taler-exchange-wirewatch.out
echo -n "."
taler-wallet-cli \
    --wallet-db="$WALLET_DB" \
    run-until-done \
    2>wallet-withdraw-finish-1.err \
    >wallet-withdraw-finish-1.out
echo " OK"

#
# CREATE INSTANCE FOR TESTING
#

echo -n "Configuring merchant admin instance ..."
if [ 1 = "$USE_FAKEBANK" ]
then
    GNUNET_PAYTO="payto://x-taler-bank/localhost/gnunet?receiver-name=gnunet"
else
    GNUNET_PAYTO=$(get_payto_uri gnunet x)
fi
STATUS=$(curl -H "Content-Type: application/json" -X POST \
    -H 'Authorization: Bearer secret-token:super_secret' \
    http://localhost:9966/management/instances \
    -d '{"auth":{"method":"external"},"id":"admin","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
    -w "%{http_code}" -s -o /dev/null)

if [ "$STATUS" != "204" ]
then
    exit_fail "Expected 204 no content. Got: $STATUS"
fi
echo "OK"

echo -n "Configuring bank account..."
STATUS=$(curl -H "Content-Type: application/json" -X POST \
    -H 'Authorization: Bearer secret-token:super_secret' \
    http://localhost:9966/private/accounts \
    -d '{"payto_uri":"'"$GNUNET_PAYTO"'","credit_facade_url":"'"${FACADE_URL}"'","credit_facade_credentials":{"type":"basic","username":"'"$FACADE_USERNAME"'","password":"'"$FACADE_PASSWORD"'"}}' \
    -w "%{http_code}" -s -o /dev/null)

if [ "$STATUS" != "200" ]
then
    exit_fail "Expected 200 OK. Got: $STATUS"
fi

echo "OK"

# CREATE ORDER AND SELL IT
echo -n "Creating order to be paid..."
STATUS=$(curl 'http://localhost:9966/private/orders' \
    -d '{"refund_delay":{"d_us":0},"order":{"amount":"TESTKUDOS:1","summary":"payme"}}' \
    -w "%{http_code}" \
    -s \
    -o "$LAST_RESPONSE")

if [ "$STATUS" != "200" ]
then
    exit_fail "Expected 200 OK. Got: $STATUS " "$(cat "$LAST_RESPONSE")"
fi

ORDER_ID=$(jq -e -r .order_id < "$LAST_RESPONSE")
STATUS=$(curl "http://localhost:9966/private/orders/${ORDER_ID}" \
              -w "%{http_code}" \
              -s \
              -o "$LAST_RESPONSE")

if [ "$STATUS" != "200" ]
then
    exit_fail "Expected 200 ok. Got: $STATUS" "$(cat "$LAST_RESPONSE")"
fi
PAY_URL=$(jq -e -r .taler_pay_uri < "$LAST_RESPONSE")
echo OK

NOW=$(date +%s)
echo -n "Pay first order ..."
taler-wallet-cli \
    --no-throttle \
    --wallet-db="$WALLET_DB" \
    handle-uri "${PAY_URL}" \
    -y 2> wallet-pay1.err > wallet-pay1.log
NOW2=$(date +%s)
echo "OK. Took $(( NOW2 -  NOW))s."

STATUS=$(curl "http://localhost:9966/private/orders/${ORDER_ID}" \
              -w "%{http_code}" \
              -s \
              -o "$LAST_RESPONSE")

if [ "$STATUS" != "200" ]
then
    exit_fail "Expected 200 Ok. Got: $STATUS" "$(cat "$LAST_RESPONSE")"
fi

ORDER_STATUS=$(jq -r .order_status < "$LAST_RESPONSE")
if [ "$ORDER_STATUS" != "paid" ]
then
    exit_fail "Expected order status 'paid'. Got: $ORDER_STATUS" "$(cat "$LAST_RESPONSE")"
fi

#
# WIRE TRANSFER TO MERCHANT AND NOTIFY BACKEND
#

WIRE_DEADLINE=$(jq -r .contract_terms.wire_transfer_deadline.t_s < "$LAST_RESPONSE")
NOW=$(date +%s)

TO_SLEEP="$(( 3600 + WIRE_DEADLINE - NOW ))"
echo -n "Perform wire transfers (with ${TO_SLEEP}s timeshift) ..."
taler-exchange-aggregator \
    -y \
    -c "$CONF" \
    -T "${TO_SLEEP}000000" \
    -t \
    -L INFO &> aggregator.log
taler-exchange-transfer\
    -c "$CONF" \
    -t \
    -L INFO &> transfer.log
echo " DONE"

if [ 1 != "$USE_FAKEBANK" ]
then
    echo -n "Waiting for Nexus and Sandbox to settle the payment ..."
    sleep 3 # FIXME-MS: replace with call to Nexus to right now poll the sandbox ...
    libeufin-cli \
        accounts \
        fetch-transactions \
        ${NEXUS_ACCOUNT_NAME} \
        &> libeufin-transfer-fetch.out
    echo " DONE"
fi

echo -n "Obtaining wire transfer details from bank..."
taler-merchant-wirewatch \
    -c "$CONF" \
    -t \
    -L INFO &> merchant-wirewatch.log
echo " OK"

echo -n "Obtaining deposit data from exchange..."
taler-merchant-depositcheck \
    -c "$CONF" \
    -e "http://localhost:8081/" \
    -T "${TO_SLEEP}000000" \
    -t \
    -L INFO &> merchant-depositcheck.log
echo " OK"

echo -n "Obtaining reconciliation data from exchange..."
taler-merchant-reconciliation \
    -c "$CONF" \
    -T "${TO_SLEEP}000000" \
    -t \
    -L INFO &> merchant-reconciliation.log
echo " OK"

echo -n "Fetching wire transfers of ADMIN instance ..."
STATUS=$(curl 'http://localhost:9966/private/transfers' \
              -w "%{http_code}" \
              -s \
              -o "$LAST_RESPONSE")
if [ "$STATUS" != "200" ]
then
    exit_fail "Expected response 200 Ok. Got: $STATUS" "$(jq . < "$LAST_RESPONSE")"
fi
TRANSFERS_LIST_SIZE=$(jq -r '.transfers | length' < "$LAST_RESPONSE")
if [ "$TRANSFERS_LIST_SIZE" != "1" ]
then
    exit_fail "Expected one transfer. Got: $TRANSFERS_LIST_SIZE" "$(jq . < "$LAST_RESPONSE")"
fi
echo " OK"

echo -n "Reconciling wire transfer data with exchange..."
taler-merchant-reconciliation \
    -c "$CONF" \
    -t \
    -L INFO &> merchant-reconciliation.log
echo " OK"

echo -n "Checking order status ..."
STATUS=$(curl "http://localhost:9966/private/orders/${ORDER_ID}?transfer=YES" \
              -w "%{http_code}" \
              -s \
              -o "$LAST_RESPONSE")

if [ "$STATUS" != "200" ]
then
    jq . < "$LAST_RESPONSE"
    exit_fail "Expected 200 ok. got: $STATUS" "$(cat "$LAST_RESPONSE")"
fi

WAS_WIRED=$(jq -r .wired < "$LAST_RESPONSE")
if [ "$WAS_WIRED" != "true" ]
then
    jq . < "$LAST_RESPONSE"
    exit_fail "Got .wired 'false', expected 'true'"
fi
echo " OK"

exit 0
