#!/bin/bash
# End-to-end iperf3 bandwidth test between FIPS nodes via DNS resolution.
# Usage: ./iperf-test.sh [mesh|chain] [--live]
#
# Requires containers to be running:
#   docker compose --profile mesh up -d
#   ./scripts/iperf-test.sh mesh
#   ./scripts/iperf-test.sh mesh --live  # Show live iperf3 output
set -e

# Exit entire script on Ctrl+C
trap 'echo ""; echo "Test interrupted"; exit 130' INT

PROFILE="${1:-mesh}"
LIVE_OUTPUT=false
if [ "$2" = "--live" ] || [ "$1" = "--live" ]; then
    LIVE_OUTPUT=true
    [ "$1" = "--live" ] && PROFILE="mesh"
fi

DURATION="${DURATION:-10}"
PARALLEL="${PARALLEL:-8}"
SETTLE_SECONDS="${SETTLE_SECONDS:-3}"
IPERF_TIMEOUT="${IPERF_TIMEOUT:-$((DURATION + 30))}"
PASSED=0
FAILED=0

# Node identities (from generated env file)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ENV_FILE="$SCRIPT_DIR/../generated-configs${FIPS_CI_NAME_SUFFIX:-}/npubs.env"
if [ ! -f "$ENV_FILE" ]; then
    echo "Error: $ENV_FILE not found. Run generate-configs.sh first." >&2
    exit 1
fi
# shellcheck source=../generated-configs/npubs.env
source "$ENV_FILE"

iperf_test() {
    local server_node="$1"
    local client_node="$2"
    local dest_npub="$3"
    local label="$4"

    echo ""
    echo "=== $label ==="
    
    # iperf3 server is already running in daemon mode in each container
    
    if [ "$LIVE_OUTPUT" = true ]; then
        # Show live output
        echo "Running iperf3 test (live output):"
        if docker exec "fips-${client_node}${FIPS_CI_NAME_SUFFIX:-}" timeout "$IPERF_TIMEOUT" iperf3 -c "${dest_npub}.fips" -t "$DURATION" -P "$PARALLEL"; then
            PASSED=$((PASSED + 1))
        else
            echo "FAIL"
            FAILED=$((FAILED + 1))
        fi
    else
        # Capture and summarize output
        echo -n "Running iperf3 test... "
        local output
        if output=$(docker exec "fips-${client_node}${FIPS_CI_NAME_SUFFIX:-}" timeout "$IPERF_TIMEOUT" iperf3 -c "${dest_npub}.fips" -t "$DURATION" -P "$PARALLEL" 2>&1); then
            # Check if we got valid results
            if echo "$output" | grep -q "sender"; then
                # Extract and display results (get SUM line for aggregate bandwidth)
                local bandwidth=$(echo "$output" | grep "\[SUM\].*sender" | tail -1 | awk '{for(i=1;i<=NF;i++) if($i ~ /bits\/sec/) {print $(i-1), $i; exit}}')
                echo "OK"
                echo "Bandwidth: $bandwidth"
                PASSED=$((PASSED + 1))
            else
                echo "FAIL (no bandwidth data)"
                echo "Output: $output"
                FAILED=$((FAILED + 1))
            fi
        else
            echo "FAIL"
            echo "Error output:"
            echo "$output" | head -10
            FAILED=$((FAILED + 1))
        fi
    fi
}

echo "=== FIPS iperf3 Bandwidth Test ($PROFILE topology) ==="
echo ""

# Print topology so the operator can see the configured routing
# context. The bench measures iperf3 throughput between the named
# nodes — labels DO NOT encode hop count, since peer discovery
# converges every same-subnet pair onto a direct UDP path within a
# few ticks regardless of the static `peers:` list.
if [ "$PROFILE" = "mesh" ]; then
    echo "Topology (static \`peers:\` from mesh.yaml):"
    echo "  A peers with: D, E"
    echo "  B peers with: C"
    echo "  C peers with: B, D, E"
    echo "  D peers with: A, C, E"
    echo "  E peers with: A, C, D"
    echo "  (Same docker-bridge subnet — discovery converges every"
    echo "   pair onto a direct UDP path; static \`peers:\` only seeds"
    echo "   the initial mesh, not the steady-state routing.)"
elif [ "$PROFILE" = "chain" ]; then
    echo "Topology (static chain): A — B — C — D — E"
    echo "  (Same docker-bridge subnet — see mesh note above.)"
fi
echo ""

# Wait for nodes to converge
echo "Waiting ${SETTLE_SECONDS}s for mesh convergence..."
sleep "$SETTLE_SECONDS"

if [ "$PROFILE" = "mesh" ]; then
    echo ""
    echo "Testing mesh topology paths:"
    iperf_test node-d node-a "$NPUB_D" "A→D"
    iperf_test node-e node-a "$NPUB_E" "A→E"
    iperf_test node-b node-a "$NPUB_B" "A→B"
    iperf_test node-c node-a "$NPUB_C" "A→C"
    iperf_test node-a node-e "$NPUB_A" "E→A"

elif [ "$PROFILE" = "chain" ]; then
    echo ""
    echo "Testing chain topology paths:"
    iperf_test node-b node-a "$NPUB_B" "A→B"
    iperf_test node-c node-a "$NPUB_C" "A→C"
    iperf_test node-d node-a "$NPUB_D" "A→D"
    iperf_test node-e node-a "$NPUB_E" "A→E"
    iperf_test node-a node-e "$NPUB_A" "E→A"
fi

echo ""
echo "=== Results: $PASSED passed, $FAILED failed ==="
[ "$FAILED" -eq 0 ] && exit 0 || exit 1
