#!/bin/bash
################################################################################
# Script Name: speedtest-metrics.sh
# Description: Prometheus exporter for internet and LAN speed metrics
#
# Collects internet speed tests via Ookla Speedtest CLI against multiple
# servers and local network tests via iperf3. Outputs Prometheus-formatted
# metrics with per-server labels.
#
# Author:  Phil Connor
# Contact: contact@mylinux.work
# Website: https://mylinux.work
# License: MIT
# Version: 3.0
#
# Usage:
#   # Output to stdout
#   ./speedtest-metrics.sh
#
#   # Textfile collector mode (atomic write)
#   ./speedtest-metrics.sh --textfile
#
#   # Custom output file
#   ./speedtest-metrics.sh -o /path/to/metrics.prom
#
#   # HTTP server mode
#   ./speedtest-metrics.sh --http
#
################################################################################

# ============================================================================
# CONFIGURATION VARIABLES
# ============================================================================

LISTEN_PORT="${SPEEDTEST_EXPORTER_PORT:-9196}"
TEXTFILE_DIR="/var/lib/node_exporter"
OUTPUT_FILE=""
HTTP_MODE=false
HOSTNAME=$(hostname)

# ============================================================================
# ARGUMENT PARSING
# ============================================================================

show_help() {
    cat <<EOF
Speedtest Metrics Exporter for Prometheus

Usage: $0 [OPTIONS]

MODES:
  --textfile             Write to node_exporter textfile collector
  --http                 Run HTTP server on port $LISTEN_PORT
  (no flag)              Output to stdout (default)

OPTIONS:
  -p, --port PORT        HTTP port (default: 9196)
  -o, --output PATH      Output file path
  --help                 Show this help

ENVIRONMENT VARIABLES:
  SPEEDTEST_SERVERS      Comma-separated Ookla server IDs or "auto" (default: auto)
  IPERF_SERVER           Local iperf3 server IP (default: 192.168.1.100)
  IPERF_PORT             iperf3 port (default: 9182)
  SPEEDTEST_EXPORTER_PORT  Same as --port

EXAMPLES:
  $0                               # One-shot to stdout
  $0 --textfile                    # Write to textfile collector
  $0 --http --port 9196            # Run HTTP server
  $0 -o /tmp/speedtest.prom        # Write to custom file

EOF
}

handle_request() {
    local request
    read -r request || true

    local path
    path=$(echo "$request" | awk '{print $2}')

    case "$path" in
        /metrics)
            local metrics
            metrics=$(collect_metrics)
            local content_length=${#metrics}
            printf "HTTP/1.1 200 OK\r\nContent-Type: text/plain; version=0.0.4; charset=utf-8\r\nContent-Length: %d\r\nConnection: close\r\n\r\n%s" "$content_length" "$metrics"
            ;;
        /)
            local body="<html><body><h1>Speedtest Metrics Exporter</h1><p><a href='/metrics'>Metrics</a></p></body></html>"
            local content_length=${#body}
            printf "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: %d\r\nConnection: close\r\n\r\n%s" "$content_length" "$body"
            ;;
        *)
            printf "HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: 9\r\nConnection: close\r\n\r\nNot Found"
            ;;
    esac
}

parse_args() {
    while [[ $# -gt 0 ]]; do
        case "$1" in
            --textfile)
                OUTPUT_FILE="$TEXTFILE_DIR/speedtest.prom"
                shift
                ;;
            --http)
                HTTP_MODE=true
                shift
                ;;
            --port|-p)
                LISTEN_PORT="$2"
                HTTP_MODE=true
                shift 2
                ;;
            --output|-o)
                OUTPUT_FILE="$2"
                shift 2
                ;;
            --handle-request)
                handle_request
                exit 0
                ;;
            --help|-h)
                show_help
                exit 0
                ;;
            *)
                echo "Unknown option: $1" >&2
                show_help >&2
                exit 1
                ;;
        esac
    done
}

parse_args "$@"

# ============================================================================
# METRICS COLLECTION
# ============================================================================

TEMP_FILE="/tmp/speedtest_$$"

cleanup() {
    rm -f "$TEMP_FILE"
}
trap cleanup EXIT

collect_metrics() {

# Configuration
IPERF_SERVER="${IPERF_SERVER:-192.168.1.100}"  # Set to your local iperf3 server IP
IPERF_PORT="${IPERF_PORT:-9182}" # iperf3 port
# Multiple speedtest servers - add/remove server IDs as needed
# Common server IDs for major cities:
# Dallas/DFW: 5029 (AT&T), 12190 (Spectrum), 26847 (Verizon)  
# New York: 3737 (Verizon), 11570 (Optimum), 17395 (Spectrum)
SPEEDTEST_SERVERS="${SPEEDTEST_SERVERS:-auto}"  # Comma-separated server IDs or "auto"

# Record script start time
SCRIPT_START_TIME=$(date +%s.%N)

# Internet Speed Test - Multiple Servers
echo "# Running internet speedtest on multiple servers..." >&2

# Initialize arrays to store results for all servers
declare -a SERVER_IDS=()
declare -a PING_LATENCIES=()
declare -a PING_JITTERS=()
declare -a PING_LOWS=()
declare -a PING_HIGHS=()
declare -a DOWNLOAD_MBPS=()
declare -a UPLOAD_MBPS=()
declare -a PACKET_LOSSES=()
declare -a EXTERNAL_IPS=()
declare -a TEST_TIMESTAMPS=()
declare -a SERVER_NAMES=()
declare -a SERVER_LOCATIONS=()
declare -a SERVER_COUNTRIES=()
declare -a ISPS=()
declare -a RESULT_URLS=()
declare -a DOWNLOAD_SIZES=()
declare -a UPLOAD_SIZES=()
declare -a SUCCESSES=()

# Convert comma-separated servers to array
IFS=',' read -ra SERVERS <<< "$SPEEDTEST_SERVERS"

# Test each server
for server_id in "${SERVERS[@]}"; do
    server_id=$(echo "$server_id" | xargs)  # Trim whitespace
    echo "# Testing server $server_id..." >&2
    
    TEMP_SERVER_FILE="/tmp/speedtest_${server_id}_$$"
    
    # Handle auto server selection vs specific server ID
    if [[ "$server_id" == "auto" ]]; then
        speedtest_cmd="speedtest --format=json"
    else
        speedtest_cmd="speedtest -s $server_id --format=json"
    fi
    
    if $speedtest_cmd --accept-license --accept-gdpr > "$TEMP_SERVER_FILE" 2>/dev/null; then
        echo "# Server $server_id: SUCCESS" >&2
        
        # Parse results for this server
        ping_latency=$(jq -r '.ping.latency // "0"' "$TEMP_SERVER_FILE")
        ping_jitter=$(jq -r '.ping.jitter // "0"' "$TEMP_SERVER_FILE")
        ping_low=$(jq -r '.ping.low // "0"' "$TEMP_SERVER_FILE")
        ping_high=$(jq -r '.ping.high // "0"' "$TEMP_SERVER_FILE")
        download_bandwidth=$(jq -r '.download.bandwidth // "0"' "$TEMP_SERVER_FILE")
        upload_bandwidth=$(jq -r '.upload.bandwidth // "0"' "$TEMP_SERVER_FILE")
        packet_loss=$(jq -r '.packetLoss // "0"' "$TEMP_SERVER_FILE")
        external_ip=$(jq -r '.interface.externalIp // "unknown"' "$TEMP_SERVER_FILE")
        
        # Handle timestamp conversion
        test_timestamp_raw=$(jq -r '.timestamp // "0"' "$TEMP_SERVER_FILE")
        if [[ "$test_timestamp_raw" != "0" ]] && [[ "$test_timestamp_raw" != "unknown" ]]; then
            test_timestamp=$(date -d "$test_timestamp_raw" +%s 2>/dev/null || echo "0")
        else
            test_timestamp=0
        fi
        
        server_name=$(jq -r '.server.name // "unknown"' "$TEMP_SERVER_FILE")
        server_location=$(jq -r '.server.location // "unknown"' "$TEMP_SERVER_FILE")
        server_country=$(jq -r '.server.country // "unknown"' "$TEMP_SERVER_FILE")
        isp=$(jq -r '.isp // "unknown"' "$TEMP_SERVER_FILE")
        result_url=$(jq -r '.result.url // "unknown"' "$TEMP_SERVER_FILE")
        download_size=$(jq -r '.download.bytes // "0"' "$TEMP_SERVER_FILE")
        upload_size=$(jq -r '.upload.bytes // "0"' "$TEMP_SERVER_FILE")
        
        # Convert from bits to Mbps (fallback to awk if bc unavailable)
        download_mbps=$(echo "scale=2; $download_bandwidth / 125000" | bc -l 2>/dev/null || echo "$download_bandwidth" | awk '{printf "%.2f", $1/125000}')
        upload_mbps=$(echo "scale=2; $upload_bandwidth / 125000" | bc -l 2>/dev/null || echo "$upload_bandwidth" | awk '{printf "%.2f", $1/125000}')
        
        success=1
    else
        echo "# Server $server_id: FAILED" >&2
        
        # Set default values for failed test
        ping_latency=0; ping_jitter=0; ping_low=0; ping_high=0
        download_mbps=0; upload_mbps=0; packet_loss=0
        external_ip="unknown"; test_timestamp=0; server_name="unknown"
        server_location="unknown"; server_country="unknown"; isp="unknown"
        result_url="unknown"; download_size=0; upload_size=0
        success=0
    fi
    
    # Store results in arrays
    SERVER_IDS+=("$server_id")
    PING_LATENCIES+=("$ping_latency")
    PING_JITTERS+=("$ping_jitter")
    PING_LOWS+=("$ping_low")
    PING_HIGHS+=("$ping_high")
    DOWNLOAD_MBPS+=("$download_mbps")
    UPLOAD_MBPS+=("$upload_mbps")
    PACKET_LOSSES+=("$packet_loss")
    EXTERNAL_IPS+=("$external_ip")
    TEST_TIMESTAMPS+=("$test_timestamp")
    SERVER_NAMES+=("$server_name")
    SERVER_LOCATIONS+=("$server_location")
    SERVER_COUNTRIES+=("$server_country")
    ISPS+=("$isp")
    RESULT_URLS+=("$result_url")
    DOWNLOAD_SIZES+=("$download_size")
    UPLOAD_SIZES+=("$upload_size")
    SUCCESSES+=("$success")
    
    # Cleanup temp file
    rm -f "$TEMP_SERVER_FILE"
done

# Local Network Speed Test (iperf3) - Enhanced with additional metrics
echo "# Testing local network speed..." >&2
if command -v iperf3 >/dev/null 2>&1; then
    # Test download from local server (we are client)
    if local_down=$(timeout 10 iperf3 -c "$IPERF_SERVER" -p "$IPERF_PORT" -t 5 -J 2>/dev/null); then
        local_download_mbps=$(echo "$local_down" | jq -r '.end.sum_received.bits_per_second // "0"' | awk '{printf "%.2f", $1/1000000}')
        local_download_bytes=$(echo "$local_down" | jq -r '.end.sum_received.bytes // "0"')
        local_download_retransmits=$(echo "$local_down" | jq -r '.end.sum_sent.retransmits // "0"')
        local_download_rtt=$(echo "$local_down" | jq -r '.end.streams[0].sender.mean_rtt // "0"' | awk '{printf "%.3f", $1/1000}') # Convert to ms
        local_download_rtt_var=$(echo "$local_down" | jq -r '.end.streams[0].sender.rtt_variance // "0"' | awk '{printf "%.3f", $1/1000}')
        local_download_cpu_local=$(echo "$local_down" | jq -r '.end.cpu_utilization_percent.host_total // "0"')
        local_download_cpu_remote=$(echo "$local_down" | jq -r '.end.cpu_utilization_percent.remote_total // "0"')
        local_download_congestion_window=$(echo "$local_down" | jq -r '.end.streams[0].sender.max_snd_cwnd // "0"')
        local_download_success=1
    else
        local_download_mbps=0; local_download_bytes=0; local_download_retransmits=0
        local_download_rtt=0; local_download_rtt_var=0; local_download_cpu_local=0
        local_download_cpu_remote=0; local_download_congestion_window=0; local_download_success=0
    fi
    
    # Test upload to local server (we are client, reverse mode)
    if local_up=$(timeout 10 iperf3 -c "$IPERF_SERVER" -p "$IPERF_PORT" -t 5 -R -J 2>/dev/null); then
        local_upload_mbps=$(echo "$local_up" | jq -r '.end.sum_sent.bits_per_second // "0"' | awk '{printf "%.2f", $1/1000000}')
        local_upload_bytes=$(echo "$local_up" | jq -r '.end.sum_sent.bytes // "0"')
        local_upload_retransmits=$(echo "$local_up" | jq -r '.end.sum_received.retransmits // "0"')
        local_upload_rtt=$(echo "$local_up" | jq -r '.end.streams[0].receiver.mean_rtt // "0"' | awk '{printf "%.3f", $1/1000}')
        local_upload_rtt_var=$(echo "$local_up" | jq -r '.end.streams[0].receiver.rtt_variance // "0"' | awk '{printf "%.3f", $1/1000}')
        local_upload_cpu_local=$(echo "$local_up" | jq -r '.end.cpu_utilization_percent.host_total // "0"')
        local_upload_cpu_remote=$(echo "$local_up" | jq -r '.end.cpu_utilization_percent.remote_total // "0"')
        local_upload_congestion_window=$(echo "$local_up" | jq -r '.end.streams[0].receiver.max_snd_cwnd // "0"')
        local_upload_success=1
    else
        local_upload_mbps=0; local_upload_bytes=0; local_upload_retransmits=0
        local_upload_rtt=0; local_upload_rtt_var=0; local_upload_cpu_local=0
        local_upload_cpu_remote=0; local_upload_congestion_window=0; local_upload_success=0
    fi
else
    echo "# iperf3 not installed, skipping local network test" >&2
    local_download_mbps=0; local_upload_mbps=0; local_download_bytes=0; local_upload_bytes=0
    local_download_retransmits=0; local_upload_retransmits=0; local_download_rtt=0; local_upload_rtt=0
    local_download_rtt_var=0; local_upload_rtt_var=0; local_download_cpu_local=0; local_upload_cpu_local=0
    local_download_cpu_remote=0; local_upload_cpu_remote=0; local_download_congestion_window=0; local_upload_congestion_window=0
    local_download_success=0; local_upload_success=0
fi

# Calculate script runtime
SCRIPT_END_TIME=$(date +%s.%N)
SCRIPT_RUNTIME=$(echo "$SCRIPT_END_TIME - $SCRIPT_START_TIME" | bc -l 2>/dev/null || echo "$SCRIPT_END_TIME $SCRIPT_START_TIME" | awk '{printf "%.3f", $1-$2}')

# Output Prometheus metrics
cat <<EOF
# HELP internet_speedtest_latency Internet connection latency in milliseconds
# TYPE internet_speedtest_latency gauge
EOF

# Generate metrics for each server
for i in "${!SERVER_IDS[@]}"; do
    server_id="${SERVER_IDS[$i]}"
    server_name="${SERVER_NAMES[$i]}"
    server_location="${SERVER_LOCATIONS[$i]}"
    server_country="${SERVER_COUNTRIES[$i]}"
    isp="${ISPS[$i]}"
    external_ip="${EXTERNAL_IPS[$i]}"
    result_url="${RESULT_URLS[$i]}"
    
    cat <<EOF
internet_speedtest_latency{hostname="$HOSTNAME",server_id="$server_id",server_name="$server_name",server_location="$server_location",server_country="$server_country"} ${PING_LATENCIES[$i]}
EOF
done

cat <<EOF

# HELP internet_speedtest_latency_low Internet connection minimum latency in milliseconds
# TYPE internet_speedtest_latency_low gauge
EOF

for i in "${!SERVER_IDS[@]}"; do
    server_id="${SERVER_IDS[$i]}"
    server_name="${SERVER_NAMES[$i]}"
    server_location="${SERVER_LOCATIONS[$i]}"
    server_country="${SERVER_COUNTRIES[$i]}"
    
    cat <<EOF
internet_speedtest_latency_low{hostname="$HOSTNAME",server_id="$server_id",server_name="$server_name",server_location="$server_location",server_country="$server_country"} ${PING_LOWS[$i]}
EOF
done

cat <<EOF

# HELP internet_speedtest_latency_high Internet connection maximum latency in milliseconds
# TYPE internet_speedtest_latency_high gauge
EOF

for i in "${!SERVER_IDS[@]}"; do
    server_id="${SERVER_IDS[$i]}"
    server_name="${SERVER_NAMES[$i]}"
    server_location="${SERVER_LOCATIONS[$i]}"
    server_country="${SERVER_COUNTRIES[$i]}"
    
    cat <<EOF
internet_speedtest_latency_high{hostname="$HOSTNAME",server_id="$server_id",server_name="$server_name",server_location="$server_location",server_country="$server_country"} ${PING_HIGHS[$i]}
EOF
done

cat <<EOF

# HELP internet_speedtest_jitter Internet connection jitter in milliseconds
# TYPE internet_speedtest_jitter gauge
EOF

for i in "${!SERVER_IDS[@]}"; do
    server_id="${SERVER_IDS[$i]}"
    server_name="${SERVER_NAMES[$i]}"
    server_location="${SERVER_LOCATIONS[$i]}"
    server_country="${SERVER_COUNTRIES[$i]}"
    
    cat <<EOF
internet_speedtest_jitter{hostname="$HOSTNAME",server_id="$server_id",server_name="$server_name",server_location="$server_location",server_country="$server_country"} ${PING_JITTERS[$i]}
EOF
done

cat <<EOF

# HELP internet_speedtest_download Internet download speed in Mbps
# TYPE internet_speedtest_download gauge
EOF

for i in "${!SERVER_IDS[@]}"; do
    server_id="${SERVER_IDS[$i]}"
    server_name="${SERVER_NAMES[$i]}"
    server_location="${SERVER_LOCATIONS[$i]}"
    server_country="${SERVER_COUNTRIES[$i]}"
    
    cat <<EOF
internet_speedtest_download{hostname="$HOSTNAME",server_id="$server_id",server_name="$server_name",server_location="$server_location",server_country="$server_country"} ${DOWNLOAD_MBPS[$i]}
EOF
done

cat <<EOF

# HELP internet_speedtest_download_size Internet download test data size in bytes
# TYPE internet_speedtest_download_size gauge
EOF

for i in "${!SERVER_IDS[@]}"; do
    server_id="${SERVER_IDS[$i]}"
    server_name="${SERVER_NAMES[$i]}"
    server_location="${SERVER_LOCATIONS[$i]}"
    server_country="${SERVER_COUNTRIES[$i]}"
    
    cat <<EOF
internet_speedtest_download_size{hostname="$HOSTNAME",server_id="$server_id",server_name="$server_name",server_location="$server_location",server_country="$server_country"} ${DOWNLOAD_SIZES[$i]}
EOF
done

cat <<EOF

# HELP internet_speedtest_upload Internet upload speed in Mbps
# TYPE internet_speedtest_upload gauge
EOF

for i in "${!SERVER_IDS[@]}"; do
    server_id="${SERVER_IDS[$i]}"
    server_name="${SERVER_NAMES[$i]}"
    server_location="${SERVER_LOCATIONS[$i]}"
    server_country="${SERVER_COUNTRIES[$i]}"
    
    cat <<EOF
internet_speedtest_upload{hostname="$HOSTNAME",server_id="$server_id",server_name="$server_name",server_location="$server_location",server_country="$server_country"} ${UPLOAD_MBPS[$i]}
EOF
done

cat <<EOF

# HELP internet_speedtest_upload_size Internet upload test data size in bytes
# TYPE internet_speedtest_upload_size gauge
EOF

for i in "${!SERVER_IDS[@]}"; do
    server_id="${SERVER_IDS[$i]}"
    server_name="${SERVER_NAMES[$i]}"
    server_location="${SERVER_LOCATIONS[$i]}"
    server_country="${SERVER_COUNTRIES[$i]}"
    
    cat <<EOF
internet_speedtest_upload_size{hostname="$HOSTNAME",server_id="$server_id",server_name="$server_name",server_location="$server_location",server_country="$server_country"} ${UPLOAD_SIZES[$i]}
EOF
done

cat <<EOF

# HELP internet_speedtest_packet_loss Internet connection packet loss percentage
# TYPE internet_speedtest_packet_loss gauge
EOF

for i in "${!SERVER_IDS[@]}"; do
    server_id="${SERVER_IDS[$i]}"
    server_name="${SERVER_NAMES[$i]}"
    server_location="${SERVER_LOCATIONS[$i]}"
    server_country="${SERVER_COUNTRIES[$i]}"
    
    cat <<EOF
internet_speedtest_packet_loss{hostname="$HOSTNAME",server_id="$server_id",server_name="$server_name",server_location="$server_location",server_country="$server_country"} ${PACKET_LOSSES[$i]}
EOF
done

cat <<EOF

# HELP internet_speedtest_timestamp Unix timestamp when test was performed
# TYPE internet_speedtest_timestamp gauge
EOF

for i in "${!SERVER_IDS[@]}"; do
    server_id="${SERVER_IDS[$i]}"
    server_name="${SERVER_NAMES[$i]}"
    server_location="${SERVER_LOCATIONS[$i]}"
    server_country="${SERVER_COUNTRIES[$i]}"
    
    cat <<EOF
internet_speedtest_timestamp{hostname="$HOSTNAME",server_id="$server_id",server_name="$server_name",server_location="$server_location",server_country="$server_country"} ${TEST_TIMESTAMPS[$i]}
EOF
done

cat <<EOF

# HELP internet_speedtest_info Internet speedtest metadata
# TYPE internet_speedtest_info gauge
EOF

for i in "${!SERVER_IDS[@]}"; do
    server_id="${SERVER_IDS[$i]}"
    server_name="${SERVER_NAMES[$i]}"
    server_location="${SERVER_LOCATIONS[$i]}"
    server_country="${SERVER_COUNTRIES[$i]}"
    external_ip="${EXTERNAL_IPS[$i]}"
    isp="${ISPS[$i]}"
    result_url="${RESULT_URLS[$i]}"
    
    cat <<EOF
internet_speedtest_info{hostname="$HOSTNAME",server_id="$server_id",server_name="$server_name",server_location="$server_location",server_country="$server_country",external_ip="$external_ip",isp="$isp",result_url="$result_url"} 1
EOF
done

cat <<EOF

# HELP internet_speedtest_success Whether internet speedtest succeeded (1=success, 0=failed)
# TYPE internet_speedtest_success gauge
EOF

for i in "${!SERVER_IDS[@]}"; do
    server_id="${SERVER_IDS[$i]}"
    server_name="${SERVER_NAMES[$i]}"
    server_location="${SERVER_LOCATIONS[$i]}"
    server_country="${SERVER_COUNTRIES[$i]}"
    
    cat <<EOF
internet_speedtest_success{hostname="$HOSTNAME",server_id="$server_id",server_name="$server_name",server_location="$server_location",server_country="$server_country"} ${SUCCESSES[$i]}
EOF
done

cat <<EOF

# HELP local_network_download Local network download speed in Mbps
# TYPE local_network_download gauge
local_network_download{hostname="$HOSTNAME"} $local_download_mbps

# HELP local_network_upload Local network upload speed in Mbps
# TYPE local_network_upload gauge
local_network_upload{hostname="$HOSTNAME"} $local_upload_mbps

# HELP local_network_download_bytes Total bytes downloaded in local network test
# TYPE local_network_download_bytes gauge
local_network_download_bytes{hostname="$HOSTNAME"} $local_download_bytes

# HELP local_network_upload_bytes Total bytes uploaded in local network test
# TYPE local_network_upload_bytes gauge
local_network_upload_bytes{hostname="$HOSTNAME"} $local_upload_bytes

# HELP local_network_download_retransmits TCP retransmissions during download test
# TYPE local_network_download_retransmits gauge
local_network_download_retransmits{hostname="$HOSTNAME"} $local_download_retransmits

# HELP local_network_upload_retransmits TCP retransmissions during upload test
# TYPE local_network_upload_retransmits gauge
local_network_upload_retransmits{hostname="$HOSTNAME"} $local_upload_retransmits

# HELP local_network_download_rtt Mean round-trip time during download test in milliseconds
# TYPE local_network_download_rtt gauge
local_network_download_rtt{hostname="$HOSTNAME"} $local_download_rtt

# HELP local_network_upload_rtt Mean round-trip time during upload test in milliseconds
# TYPE local_network_upload_rtt gauge
local_network_upload_rtt{hostname="$HOSTNAME"} $local_upload_rtt

# HELP local_network_download_rtt_variance RTT variance during download test in milliseconds
# TYPE local_network_download_rtt_variance gauge
local_network_download_rtt_variance{hostname="$HOSTNAME"} $local_download_rtt_var

# HELP local_network_upload_rtt_variance RTT variance during upload test in milliseconds
# TYPE local_network_upload_rtt_variance gauge
local_network_upload_rtt_variance{hostname="$HOSTNAME"} $local_upload_rtt_var

# HELP local_network_download_cpu_local Local CPU utilization during download test (percentage)
# TYPE local_network_download_cpu_local gauge
local_network_download_cpu_local{hostname="$HOSTNAME"} $local_download_cpu_local

# HELP local_network_upload_cpu_local Local CPU utilization during upload test (percentage)
# TYPE local_network_upload_cpu_local gauge
local_network_upload_cpu_local{hostname="$HOSTNAME"} $local_upload_cpu_local

# HELP local_network_download_cpu_remote Remote CPU utilization during download test (percentage)
# TYPE local_network_download_cpu_remote gauge
local_network_download_cpu_remote{hostname="$HOSTNAME"} $local_download_cpu_remote

# HELP local_network_upload_cpu_remote Remote CPU utilization during upload test (percentage)
# TYPE local_network_upload_cpu_remote gauge
local_network_upload_cpu_remote{hostname="$HOSTNAME"} $local_upload_cpu_remote

# HELP local_network_download_congestion_window Maximum TCP congestion window size during download test in bytes
# TYPE local_network_download_congestion_window gauge
local_network_download_congestion_window{hostname="$HOSTNAME"} $local_download_congestion_window

# HELP local_network_upload_congestion_window Maximum TCP congestion window size during upload test in bytes
# TYPE local_network_upload_congestion_window gauge
local_network_upload_congestion_window{hostname="$HOSTNAME"} $local_upload_congestion_window

# HELP local_network_test_success Whether local network test succeeded (1=success, 0=failed)
# TYPE local_network_test_success gauge
local_network_test_success{hostname="$HOSTNAME"} $((local_download_success && local_upload_success))

# HELP speedtest_script_runtime_seconds Total script execution time in seconds
# TYPE speedtest_script_runtime_seconds gauge
speedtest_script_runtime_seconds{hostname="$HOSTNAME"} $SCRIPT_RUNTIME
EOF

}

# ============================================================================
# OUTPUT HANDLING
# ============================================================================

write_output() {
    local metrics
    metrics=$(collect_metrics)

    if [[ -n "$OUTPUT_FILE" ]]; then
        mkdir -p "$(dirname "$OUTPUT_FILE")"
        local tmp_file="${OUTPUT_FILE}.$$"
        echo "$metrics" > "$tmp_file"
        mv "$tmp_file" "$OUTPUT_FILE"
        echo "Metrics written to $OUTPUT_FILE" >&2
    else
        echo "$metrics"
    fi
}

start_server() {
    if ! command -v socat >/dev/null 2>&1; then
        echo "socat is required for HTTP mode. Install it first." >&2
        exit 1
    fi
    echo "Starting Speedtest Metrics Exporter on port $LISTEN_PORT" >&2
    echo "Metrics available at http://localhost:$LISTEN_PORT/metrics" >&2
    while true; do
        socat TCP-LISTEN:"$LISTEN_PORT",reuseaddr,fork EXEC:"$0 --handle-request" 2>/dev/null || {
            echo "Server error, restarting in 5 seconds..." >&2
            sleep 5
        }
    done
}

# Main execution
if [[ "$HTTP_MODE" == true ]]; then
    start_server
elif [[ -n "$OUTPUT_FILE" ]]; then
    write_output
else
    collect_metrics
fi
