#!/usr/bin/env bash
# run_streamhub.sh — Launch a MARTe2 app with UDPStreamer + StreamHub
#
# Usage:
#   ./run_streamhub.sh [OPTIONS]
#
# Options:
#   -m <MARTe2_DIR>              Override MARTe2 installation dir (default: $MARTe2_DIR)
#   -c <MARTe2_Components_DIR>   Override MARTe2-components dir (default: $MARTe2_Components_DIR)
#   -b <BUILD_TARGET>            Build target (default: x86-linux)
#   -p <WS_PORT>                 StreamHub WebSocket port (default: 8090)
#   -n <MAX_POINTS>              StreamHub ring-buffer size per signal (default: 10000)
#   -s                           Skip building — run with whatever is already built
#   -g                           Launch the ImGui desktop client after start
#   -w                           Build and launch the web UI server (Client/webui)
#   -h                           Show this help
#
# Ports used:
#   44500/udp   UDPStreamer scalar signals (unicast control)
#   44503/udp   UDPStreamer scalar signals (multicast data, group 239.0.0.1)
#   44501/udp   UDPStreamer array signals (FirstSample / LastSample)
#   44502/udp   UDPStreamer array signals (FullArray)
#   8080/tcp    DebugService control
#   8081/udp    DebugService stream
#   9090/tcp    TCPLogger
#   8090/tcp    StreamHub WebSocket (default, override with -p)
#
# Environment:
#   MARTe2_DIR             must be set (or passed via -m)
#   MARTe2_Components_DIR  must be set (or passed via -c)

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=8090
MAX_POINTS=1000000
SKIP_BUILD=0
START_GUI=0
START_WEBUI=0
WEBUI_PORT=8080

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

# ── Validate environment ──────────────────────────────────────────────────────
if [[ -z "${MARTe2_DIR:-}" ]]; then
    echo "ERROR: MARTe2_DIR is not set. Source env.sh first or pass -m <dir>."
    echo "  source ${SCRIPT_DIR}/env.sh"
    exit 1
fi
if [[ -z "${MARTe2_Components_DIR:-}" ]]; then
    echo "ERROR: MARTe2_Components_DIR is not set. Source env.sh first or pass -c <dir>."
    exit 1
fi

BUILD_DIR="${SCRIPT_DIR}/Build/${BUILD_TARGET}"
STREAMHUB_EX="${BUILD_DIR}/StreamHub/StreamHub.ex"
IMGUI_CLIENT="${SCRIPT_DIR}/Client/streamhub/build/StreamHubClient"
WEBUI_DIR="${SCRIPT_DIR}/Client/webui"
WEBUI_BIN="${WEBUI_DIR}/streamhub-webui"

MARTE2_BIN="${MARTe2_DIR}/Build/${BUILD_TARGET}/App/MARTeApp.ex"
if [[ ! -x "$MARTE2_BIN" ]]; then
    MARTE2_BIN="${MARTe2_DIR}/Build/${BUILD_TARGET}/App/MARTe2.sh"
fi
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 (TARGET=${BUILD_TARGET})..."
    make -C "${SCRIPT_DIR}" -f Makefile.gcc TARGET="${BUILD_TARGET}" 2>&1 | tail -10

    echo "==> Building StreamHub (TARGET=${BUILD_TARGET})..."
    make -C "${SCRIPT_DIR}/Source/Applications/StreamHub" \
         -f Makefile.gcc TARGET="${BUILD_TARGET}" \
         MARTe2_DIR="${MARTe2_DIR}" 2>&1 | tail -10

    if [[ "$START_GUI" -eq 1 ]]; then
        if [[ -d "${SCRIPT_DIR}/Client/streamhub/build" ]]; then
            echo "==> Building ImGui client (a full rebuild can take ~2 min;"
            echo "    ImPlot's implot_items.cpp is one slow -O3 translation unit)..."
            cmake --build "${SCRIPT_DIR}/Client/streamhub/build" -j"$(nproc)"
        fi
    fi

    if [[ "$START_WEBUI" -eq 1 ]]; then
        echo "==> Building web UI server..."
        (cd "${WEBUI_DIR}" && go build -o streamhub-webui .)
    fi

    echo "==> Build done."
fi

# ── Sanity-check binaries ─────────────────────────────────────────────────────
if [[ ! -x "$STREAMHUB_EX" ]]; then
    echo "ERROR: StreamHub binary not found: ${STREAMHUB_EX}"
    echo "  Build it with: make -C Source/Applications/StreamHub -f Makefile.gcc"
    exit 1
fi

# ── Write StreamHub config ────────────────────────────────────────────────────
HUB_CFG="$(mktemp /tmp/streamhub_XXXXXX.cfg)"

cat > "$HUB_CFG" <<EOF
/**
 * StreamHub configuration — auto-generated by run_streamhub.sh
 *
 * Three sources matching the streamhub_demo MARTe2 configuration:
 *   scalar  : 1 kHz scalar sines @ 1 ksps  (Sine1, Sine2)
 *   med     : 1 kHz arrays @ 1 Msps        (Ch1, Ch2)
 *   fast    : 5 kHz arrays @ 5 Msps        (Ch3, Ch4)
 */
Hub = {
    WSPort        = ${WS_PORT}
    MaxPoints     = ${MAX_POINTS}
    PushRate      = 30
    MaxPushPoints = 2000
    RingTemporal  = 1000000
    RingScalar    = 100000
    +History = {
        Directory      = "/tmp/streamhub_history"
        DurationHours  = 1
        Decimation     = 10
        FlushIntervalSec = 5
        MinDiskFreeMB  = 200
    }
    +Recorder = {
        Enabled          = 0
        AutoStart        = 1
        Directory        = "/tmp/streamhub_rec"
        MaxFileMB        = 256
        KeepFiles        = 8
        StagingMB        = 8
        FlushIntervalSec = 5
        MinDiskFreeMB    = 500
        Signals          = "all"
    }
    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

# ── Library path — covers both MARTe2 app and StreamHub ──────────────────────
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:-}"

# ── Cleanup handler ───────────────────────────────────────────────────────────
MARTE_PID=""
HUB_PID=""
GUI_PID=""
WEBUI_PID=""

cleanup() {
    echo ""
    echo "==> Shutting down..."
    [[ -n "$WEBUI_PID" ]] && kill "$WEBUI_PID" 2>/dev/null || true
    [[ -n "$GUI_PID"   ]] && kill "$GUI_PID"   2>/dev/null || true
    [[ -n "$HUB_PID"   ]] && kill "$HUB_PID"   2>/dev/null || true
    [[ -n "$MARTE_PID" ]] && kill "$MARTE_PID" 2>/dev/null || true
    wait "$WEBUI_PID" 2>/dev/null || true
    wait "$GUI_PID"   2>/dev/null || true
    wait "$HUB_PID"   2>/dev/null || true
    wait "$MARTE_PID" 2>/dev/null || true
    rm -f "$HUB_CFG"
    echo "==> Done."
}
trap cleanup EXIT INT TERM

# ── Launch MARTe2 ─────────────────────────────────────────────────────────────
echo ""
echo "==> Launching MARTe2..."
echo "    Binary : ${MARTE2_BIN}"
echo "    Config : ${MARTe_CFG}"
echo "    Signals: Sine1 (1 Hz), Sine2 (0.3 Hz), Ch1-Ch4 (arrays)"
echo ""

"${MARTE2_BIN}" \
    -l RealTimeLoader \
    -f "${MARTe_CFG}" \
    -s Running \
    -m StateMachine:START &
MARTE_PID="$!"

# Give MARTe2 a moment to bind its UDP ports before StreamHub connects
sleep 1

# ── Launch StreamHub ──────────────────────────────────────────────────────────
echo "==> Launching StreamHub..."
echo "    Binary   : ${STREAMHUB_EX}"
echo "    Config   : ${HUB_CFG}"
echo "    WS port  : ${WS_PORT}"
echo "    MaxPoints: ${MAX_POINTS}"
echo ""

"${STREAMHUB_EX}" -cfg "${HUB_CFG}" &
HUB_PID="$!"

# ── Optionally launch the ImGui client ───────────────────────────────────────
if [[ "$START_GUI" -eq 1 ]]; then
    if [[ ! -x "$IMGUI_CLIENT" ]]; then
        echo "WARNING: ImGui client not found at ${IMGUI_CLIENT}"
        echo "  Build it with: cd Client/streamhub && cmake -B build && cmake --build build"
    else
        sleep 0.5
        echo "==> Launching ImGui client (127.0.0.1:${WS_PORT})..."
        "${IMGUI_CLIENT}" -host 127.0.0.1 -port "${WS_PORT}" &
        GUI_PID="$!"
    fi
fi

# ── Optionally launch the web UI server ──────────────────────────────────────
if [[ "$START_WEBUI" -eq 1 ]]; then
    if [[ ! -x "$WEBUI_BIN" ]]; then
        echo "WARNING: webui binary not found at ${WEBUI_BIN}"
        echo "  Build it with: cd Client/webui && go build -o streamhub-webui ."
    else
        echo "==> Launching web UI server (:${WEBUI_PORT})..."
        "${WEBUI_BIN}" -addr ":${WEBUI_PORT}" \
            -hub "localhost:${WS_PORT}" \
            -static "${SCRIPT_DIR}/Client/udpstreamer/static" &
        WEBUI_PID="$!"
    fi
fi

# ── Status ────────────────────────────────────────────────────────────────────
echo "    MARTe2 PID   : ${MARTE_PID}"
echo "    StreamHub PID: ${HUB_PID}"
[[ -n "$GUI_PID"   ]] && echo "    ImGui PID    : ${GUI_PID}"
[[ -n "$WEBUI_PID" ]] && echo "    WebUI PID    : ${WEBUI_PID}"
echo ""
echo "    StreamHub WebSocket: ws://127.0.0.1:${WS_PORT}"
[[ -n "$WEBUI_PID" ]] && echo "    Browser client    : http://localhost:${WEBUI_PORT}/"
[[ -x "$IMGUI_CLIENT" ]] && echo "    ImGui client      : ${IMGUI_CLIENT} -host 127.0.0.1 -port ${WS_PORT}"
echo ""
echo "    Press Ctrl-C to stop all processes."
echo ""

# ── Wait until any child exits ────────────────────────────────────────────────
wait -n "${MARTE_PID}" "${HUB_PID}" ${GUI_PID:-} ${WEBUI_PID:-} 2>/dev/null || true
echo "==> A process exited — stopping remaining processes."
