#!/usr/bin/env bash
# run_e2e_test.sh — End-to-end test of the streaming pipeline:
#   MARTe2 app (UDPStreamer) → StreamHub (C++) → WebSocket client (Go)
#
# Launches the full stack headless, then runs Test/E2E/streamhub which
# verifies sources/config events, binary data pushes (wall-clock time base,
# per-signal monotonicity), stats, WS zoom round-trips and a hub-side
# trigger capture.  Exits 0 iff every check passes.
#
# Usage:
#   ./run_e2e_test.sh [OPTIONS]
#
# Options:
#   -m <MARTe2_DIR>              Override MARTe2 installation dir
#   -c <MARTe2_Components_DIR>   Override MARTe2-components dir
#   -b <BUILD_TARGET>            Build target (default: x86-linux)
#   -p <WS_PORT>                 StreamHub WebSocket port (default: 8095)
#   -s                           Skip building
#   -h                           Show this help

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MARTe_CFG="${SCRIPT_DIR}/Test/Configurations/streamhub_demo.cfg"
BUILD_TARGET="${TARGET:-x86-linux}"
WS_PORT=8095
SKIP_BUILD=0

while getopts "m:c:b:p:sh" opt; do
    case "$opt" in
        m) MARTe2_DIR="$OPTARG" ;;
        c) MARTe2_Components_DIR="$OPTARG" ;;
        b) BUILD_TARGET="$OPTARG" ;;
        p) WS_PORT="$OPTARG" ;;
        s) SKIP_BUILD=1 ;;
        h)
            sed -n '2,19p' "$0" | grep '^#' | sed 's/^# \?//'
            exit 0
            ;;
        *) echo "Unknown option: -$OPTARG" >&2; exit 1 ;;
    esac
done

if [[ -z "${MARTe2_DIR:-}" || -z "${MARTe2_Components_DIR:-}" ]]; then
    echo "ERROR: MARTe2_DIR / MARTe2_Components_DIR not set. Source env.sh first."
    exit 1
fi

BUILD_DIR="${SCRIPT_DIR}/Build/${BUILD_TARGET}"
STREAMHUB_EX="${BUILD_DIR}/StreamHub/StreamHub.ex"
E2E_DIR="${SCRIPT_DIR}/Test/E2E/streamhub"
E2E_BIN="${E2E_DIR}/streamhub-e2e"

MARTE2_BIN="${MARTe2_DIR}/Build/${BUILD_TARGET}/App/MARTeApp.ex"
[[ -x "$MARTE2_BIN" ]] || MARTE2_BIN="${MARTe2_DIR}/Build/${BUILD_TARGET}/App/MARTe2.sh"
if [[ ! -x "$MARTE2_BIN" ]]; then
    echo "ERROR: MARTe2 executable not found at ${MARTe2_DIR}/Build/${BUILD_TARGET}/App/"
    exit 1
fi

# ── Build ─────────────────────────────────────────────────────────────────────
if [[ "$SKIP_BUILD" -eq 0 ]]; then
    echo "==> Building MARTe2 components + StreamHub..."
    make -C "${SCRIPT_DIR}" -f Makefile.gcc TARGET="${BUILD_TARGET}" core apps 2>&1 | tail -5
    echo "==> Building E2E client..."
    (cd "${E2E_DIR}" && go build -o streamhub-e2e .)
fi

if [[ ! -x "$STREAMHUB_EX" ]]; then
    echo "ERROR: StreamHub binary not found: ${STREAMHUB_EX}"
    exit 1
fi

# ── StreamHub config ──────────────────────────────────────────────────────────
HUB_CFG="$(mktemp /tmp/streamhub_e2e_XXXXXX.cfg)"
cat > "$HUB_CFG" <<EOF
Hub = {
    WSPort       = ${WS_PORT}
    MaxPoints    = 20000
    PushRate     = 30
    RingTemporal = 1000000
    RingScalar   = 100000
    +History = {
        Directory      = "/tmp/streamhub_e2e_history"
        DurationHours  = 0.1
        Decimation     = 10
        FlushIntervalSec = 2
        MinDiskFreeMB  = 100
    }
    Sources = {
        scalar = {
            Label          = "Scalar Sines (1 ksps)"
            Addr           = "127.0.0.1"
            Port           = 44500
            MulticastGroup = "239.0.0.1"
            DataPort       = 44503
        }
        med = {
            Label = "1 Msps Sines (Ch1 1kHz, Ch2 5kHz)"
            Addr  = "127.0.0.1"
            Port  = 44501
        }
        fast = {
            Label = "5 Msps Sines (Ch3 10kHz, Ch4 50kHz)"
            Addr  = "127.0.0.1"
            Port  = 44502
        }
    }
}
EOF

export LD_LIBRARY_PATH="\
${MARTe2_DIR}/Build/${BUILD_TARGET}/Core:\
${MARTe2_Components_DIR}/Build/${BUILD_TARGET}/Components/DataSources/LinuxTimer:\
${MARTe2_Components_DIR}/Build/${BUILD_TARGET}/Components/GAMs/IOGAM:\
${BUILD_DIR}/Components/DataSources/UDPStreamer:\
${BUILD_DIR}/Components/GAMs/SineArrayGAM:\
${BUILD_DIR}/Components/GAMs/TimeArrayGAM:\
${BUILD_DIR}/Components/Interfaces/UDPStream:\
${LD_LIBRARY_PATH:-}"

MARTE_PID=""
HUB_PID=""
RESULT=1

cleanup() {
    [[ -n "$HUB_PID"   ]] && kill "$HUB_PID"   2>/dev/null || true
    [[ -n "$MARTE_PID" ]] && kill "$MARTE_PID" 2>/dev/null || true
    wait "$HUB_PID"   2>/dev/null || true
    wait "$MARTE_PID" 2>/dev/null || true
    rm -f "$HUB_CFG"
    if [[ "$RESULT" -eq 0 ]]; then
        echo "==> E2E: PASS"
    else
        echo "==> E2E: FAIL"
    fi
}
trap cleanup EXIT INT TERM

echo "==> Launching MARTe2 (headless)..."
"${MARTE2_BIN}" \
    -l RealTimeLoader \
    -f "${MARTe_CFG}" \
    -s Running \
    -m StateMachine:START > /tmp/streamhub_e2e_marte.log 2>&1 &
MARTE_PID="$!"

sleep 1

echo "==> Launching StreamHub (ws port ${WS_PORT})..."
"${STREAMHUB_EX}" -cfg "${HUB_CFG}" > /tmp/streamhub_e2e_hub.log 2>&1 &
HUB_PID="$!"

# Give the hub time to connect the UDPS sources and fill some history
sleep 3

echo "==> Running E2E client..."
if "${E2E_BIN}" -hub "127.0.0.1:${WS_PORT}" -timeout 60s; then
    RESULT=0
fi

exit "$RESULT"
