#!/bin/bash
set -e

# pg_virtualenv does its cluster setup as the invoking user. When
# autopkgtest runs as root, re-exec as the postgres system user so the
# cluster is owned by an unprivileged account. We use "su" without the
# "-"/login flag to preserve the environment (notably AUTOPKGTEST_TMP)
# and force /bin/sh so we don't depend on the postgres user's shell.
# Positional args after the username become $0, $1, ... of the -c shell;
# we pass our script path so it becomes $0 and re-execs via its shebang.
if [ "$(id -u)" = 0 ]; then
    exec su -s /bin/sh postgres -c 'exec "$0" "$@"' "$0" "$@"
fi

BARMAN_HOME=
BARMAN_CONF=
receiver_pid=

cleanup() {
    echo "Cleaning up..."
    # "barman receive-wal --stop" signals the daemon via its pidfile,
    # which is more reliable than killing our background job (barman
    # forks pg_receivewal, and the child may not be in our process
    # group).
    if [ -n "$BARMAN_CONF" ] && [ -r "$BARMAN_CONF" ]; then
        barman -c "$BARMAN_CONF" receive-wal --stop testdb 2>/dev/null || true
    fi
    if [ -n "$receiver_pid" ]; then
        wait "$receiver_pid" 2>/dev/null || true
    fi
    [ -n "$BARMAN_HOME" ] && rm -rf "$BARMAN_HOME"
    [ -n "$BARMAN_CONF" ] && rm -f "$BARMAN_CONF"
    :
}

# Poll pg_replication_slots until the given slot is active (i.e. a
# receiver is connected and streaming) or the timeout expires.
wait_for_slot_active() {
    local slot="$1"
    local timeout="${2:-30}"
    local elapsed=0 active
    while [ "$elapsed" -lt "$timeout" ]; do
        active=$(psql -AqtX -c \
            "SELECT active FROM pg_replication_slots WHERE slot_name = '$slot'" \
            2>/dev/null || true)
        if [ "$active" = "t" ]; then
            return 0
        fi
        sleep 1
        elapsed=$((elapsed + 1))
    done
    return 1
}

run_barman_test() {
    BARMAN_HOME=$(mktemp -d)
    BARMAN_CONF=$(mktemp)
    mkdir -p "$BARMAN_HOME/conf.d"

    local barman_password="barman_autopkgtest"
    local streaming_password="streaming_autopkgtest"

    echo "=== Creating PostgreSQL users ==="
    psql -c "CREATE USER barman SUPERUSER PASSWORD '$barman_password';"
    psql -c "CREATE USER streaming_barman REPLICATION LOGIN PASSWORD '$streaming_password';"

    echo "=== Configuring pg_hba for password authentication ==="
    local hba_file
    hba_file=$(psql -AqtX -c "SHOW hba_file")
    printf "host all barman 127.0.0.1/32 scram-sha-256\n" >> "$hba_file"
    printf "host replication streaming_barman 127.0.0.1/32 scram-sha-256\n" >> "$hba_file"
    psql -c "SELECT pg_reload_conf();"

    echo "=== Creating barman configuration ==="

    cat > "$BARMAN_CONF" <<EOF
[barman]
barman_home = ${BARMAN_HOME}
barman_user = $(whoami)
log_file = ${BARMAN_HOME}/barman.log
configuration_files_directory = ${BARMAN_HOME}/conf.d

[testdb]
description = "Autopkgtest PostgreSQL server"
conninfo = host=127.0.0.1 port=${PGPORT} user=barman password=${barman_password} dbname=postgres sslmode=disable
streaming_conninfo = host=127.0.0.1 port=${PGPORT} user=streaming_barman password=${streaming_password} sslmode=disable
backup_method = postgres
streaming_archiver = on
slot_name = barman
backup_directory = ${BARMAN_HOME}/testdb
EOF

    echo "=== Testing barman connectivity ==="
    barman -c "$BARMAN_CONF" list-servers
    barman -c "$BARMAN_CONF" status testdb || true

    echo "=== Creating replication slot ==="
    barman -c "$BARMAN_CONF" receive-wal --create-slot testdb

    echo "=== Starting WAL receiver (background) ==="
    barman -c "$BARMAN_CONF" receive-wal testdb &
    receiver_pid=$!

    echo "=== Waiting for WAL receiver to connect ==="
    if ! wait_for_slot_active "barman" 30; then
        echo "ERROR: WAL receiver did not connect within 30s"
        exit 1
    fi

    echo "=== Barman check (for diagnostics) ==="
    barman -c "$BARMAN_CONF" check testdb || true

    # Run the backup without --wait: --wait blocks until the backup's
    # trailing WAL is archived (moved from streaming/ to wals/), which
    # requires "barman cron" / "barman archive-wal" to run periodically.
    # This test only validates the backup path, so we skip the archive
    # step and verify the backup metadata directly.
    echo "=== Running streaming backup ==="
    barman -c "$BARMAN_CONF" backup testdb

    echo "=== Listing backups ==="
    barman -c "$BARMAN_CONF" list-backups testdb

    echo "=== Checking backup info ==="
    local backup_id
    backup_id=$(barman -c "$BARMAN_CONF" list-backups testdb --minimal | head -n 1)
    if [ -z "$backup_id" ]; then
        echo "ERROR: No backup found"
        exit 1
    fi
    barman -c "$BARMAN_CONF" show-backup testdb "$backup_id"

    echo "=== All streaming backup tests passed ==="
}

start_virtualenv() {
    PGVIRTUAL=1 exec pg_virtualenv -t \
        -o "wal_level=replica" \
        -o "max_wal_senders=3" \
        -o "max_replication_slots=3" \
        -o "listen_addresses=localhost" \
        -o "log_line_prefix=" \
        "$0"
}

trap cleanup EXIT

if [ -z "$PGVIRTUAL" ]; then
    start_virtualenv
fi

run_barman_test
