#!/bin/bash
# This file is part of Anastasis
# Copyright (C) 2026 Anastasis SARL
#
# Anastasis is free software; you can redistribute it and/or modify it under the
# terms of the GNU Affero General Public License as published by the Free Software
# Foundation; either version 3, or (at your option) any later version.
#
# Anastasis 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License along with
# Anastasis; see the file COPYING.GPL.  If not, see <http://www.gnu.org/licenses/>
#
# Check the multi-currency configuration rules that anastasis-httpd enforces
# at startup: a price must be uniformly free or uniformly priced, and a
# priced option must cover exactly [anastasis] CURRENCIES.
#
# Needs neither a database nor any Taler service.  Every case below is
# decided while the configuration is parsed, which happens before
# anastasis-httpd connects to anything.
set -eu

# Exit code for skipped tests, as expected by meson.
SKIP=77

if ! anastasis-httpd --help > /dev/null 2> /dev/null
then
    echo "anastasis-httpd not found, skipping"
    exit $SKIP
fi

WORK_DIR=$(mktemp -p "${TMPDIR:-/tmp}" -d test-anastasis-currencies-XXXXXX)
# shellcheck disable=SC2317
cleanup () {
    rm -rf "$WORK_DIR"
}
trap cleanup EXIT

BASE="$(pwd)/test_reducer.conf"
LOG="$WORK_DIR/httpd.log"

# Start anastasis-httpd on test_reducer.conf plus the given overrides and
# report whether the price lists were accepted.  Prints "accepted" or
# "refused"; the log is left in $LOG.
#
# The verdict is read off the log rather than off the exit status on
# purpose: this configuration is deliberately incomplete in other ways
# (no BUSINESS_NAME, no initialised database), so the process stops
# either way and only *why* it stopped distinguishes the cases.
try_config ()
{
    cat > "$WORK_DIR/test.conf" <<EOF
@INLINE@ $BASE
$1
EOF
    anastasis-httpd -c "$WORK_DIR/test.conf" > "$LOG" 2>&1 &
    local pid=$!
    sleep 1
    kill "$pid" 2> /dev/null || true
    wait "$pid" 2> /dev/null || true
    if grep -q "Price list error" "$LOG"
    then
        echo "refused"
    else
        echo "accepted"
    fi
}

fail ()
{
    cat "$LOG"
    echo "FAIL: $1"
    exit 1
}

# A configuration that prices everything in both currencies; each case
# below deviates from it in exactly one option.
GOOD="[anastasis]
CURRENCIES = TESTKUDOS;EUR
ANNUAL_FEE = TESTKUDOS:4.99;EUR:4
TRUTH_UPLOAD_FEE = TESTKUDOS:0.01;EUR:0.01
INSURANCE = TESTKUDOS:1.0;EUR:1.0

[authorization-question]
COST = TESTKUDOS:0.0;EUR:0.0"

echo -n "Test that a well-formed multi-currency configuration is accepted ..."
RES=$(try_config "$GOOD")
if [ "$RES" != "accepted" ]
then
    fail "anastasis-httpd rejected a well-formed multi-currency configuration"
fi
echo " OK"

echo -n "Test that a mixed free/priced option is refused ..."
RES=$(try_config "${GOOD}

[anastasis]
ANNUAL_FEE = TESTKUDOS:4.99;EUR:0")
if [ "$RES" != "refused" ]
then
    fail "anastasis-httpd accepted ANNUAL_FEE = TESTKUDOS:4.99;EUR:0"
fi
# The diagnostic has to name the option, or an operator cannot act on it.
if ! grep -q "ANNUAL_FEE" "$LOG"
then
    fail "refusal did not name the offending option"
fi
echo " OK"

echo -n "Test that an option missing a currency is refused ..."
RES=$(try_config "${GOOD}

[anastasis]
TRUTH_UPLOAD_FEE = TESTKUDOS:0.01")
if [ "$RES" != "refused" ]
then
    fail "anastasis-httpd accepted a TRUTH_UPLOAD_FEE missing EUR"
fi
if ! grep -q "TRUTH_UPLOAD_FEE" "$LOG" || ! grep -q "EUR" "$LOG"
then
    fail "refusal did not name the option and the missing currency"
fi
echo " OK"

echo -n "Test that an option priced in an undeclared currency is refused ..."
RES=$(try_config "${GOOD}

[anastasis]
TRUTH_UPLOAD_FEE = TESTKUDOS:0.01;EUR:0.01;CHF:0.01")
if [ "$RES" != "refused" ]
then
    fail "anastasis-httpd accepted a fee in a currency not in CURRENCIES"
fi
if ! grep -q "CHF" "$LOG"
then
    fail "refusal did not name the undeclared currency"
fi
echo " OK"

echo -n "Test that an option free in every currency is accepted ..."
# Zero is a first-class answer: it is how an operator says a method costs
# nothing, e.g. because the IBAN transfer is already the cost of using it.
RES=$(try_config "${GOOD}

[authorization-question]
COST = TESTKUDOS:0;EUR:0")
if [ "$RES" != "accepted" ]
then
    fail "anastasis-httpd rejected an all-zero COST"
fi
echo " OK"

echo -n "Test that an empty option means free ..."
RES=$(try_config "${GOOD}

[authorization-question]
COST =")
if [ "$RES" != "accepted" ]
then
    fail "anastasis-httpd rejected an empty COST"
fi
echo " OK"

echo -n "Test that a single-currency configuration still works ..."
# No CURRENCIES option at all: this is every configuration written before
# multi-currency support, and none of them may break.
RES=$(try_config "")
if [ "$RES" != "accepted" ]
then
    fail "anastasis-httpd rejected a single-currency configuration"
fi
echo " OK"

exit 0
