#!/usr/bin/env bash
# test-rpm.sh — Test ja4ebpf via RPM sur les 3 distros × 3 stacks
#
# Usage:
#   make rpm-ja4ebpf && ./tests/vm/test-rpm.sh [VM] [STACK]
#   ./tests/vm/test-rpm.sh rocky9 nginx
#   ./tests/vm/test-rpm.sh all all
#
# VMs:    centos8 rocky9 rocky10 (or "all")
# Stacks: nginx apache hitch-varnish (or "all")
set -euo pipefail

PROJECT_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
VM_DIR="$PROJECT_ROOT/tests/vm"
RPM_BASE="$PROJECT_ROOT/services/ja4ebpf/dist/output"

# Timeouts (seconds)
TEST_TIMEOUT=120      # max per VM×stack test
SSH_TIMEOUT=90        # max per SSH command
UPLOAD_TIMEOUT=60     # max for RPM upload

VM="${1:-rocky9}"
STACK="${2:-nginx}"

# Wrapper vagrant — always runs from the Vagrantfile directory
v() { (cd "$VM_DIR" && command vagrant "$@"); }

# SSH with timeout — uses bash -c to avoid timeout+function issue
vssh() {
    local VM="$1"; shift
    timeout "$SSH_TIMEOUT" bash -c "cd '$VM_DIR' && vagrant ssh '$VM' -- \"\$@\"" -- "$@" 2>/dev/null
}

vm_to_el() {
    case "$1" in
        centos8) echo "el8" ;;
        rocky9)  echo "el9" ;;
        rocky10) echo "el10" ;;
        *) echo "UNKNOWN" ;;
    esac
}

ALL_VMS="centos8 rocky9 rocky10"
ALL_STACKS="nginx apache hitch-varnish"
[ "$VM" = "all" ] && VMS="$ALL_VMS" || VMS="$VM"
[ "$STACK" = "all" ] && STACKS="$ALL_STACKS" || STACKS="$STACK"

PASS=0; FAIL=0; SKIP=0; RESULTS=()

echo "╔══════════════════════════════════════════════════════════════╗"
echo "║  Test RPM ja4ebpf : VMS=$VMS  STACKS=$STACKS"
echo "╚══════════════════════════════════════════════════════════════╝"

# Check RPMs exist
for vm in $VMS; do
    el=$(vm_to_el "$vm")
    rpm=$(ls -t $RPM_BASE/$el/ja4ebpf-*.rpm 2>/dev/null | head -1)
    if [ -z "$rpm" ]; then
        echo "ERROR: no RPM for $vm ($el) in $RPM_BASE/$el/"; echo "Run: make rpm-ja4ebpf"; exit 1
    fi
    echo "  $vm → $(basename $rpm)"
done

# ── Generate remote setup script ─────────────────────────────────────

generate_setup_script() {
    local STACK="$1"
    local SETUP_SCRIPT="/tmp/ja4-setup-$$$.sh"

    cat > "$SETUP_SCRIPT" << 'SETUP_EOF'
#!/bin/bash
STACK="__STACK__"

# ── Stack functions ──────────────────────────────────────────────────

setup_nginx() {
    mkdir -p /run/nginx /var/www/html
    echo '{"ok":true}' > /var/www/html/health
    openssl req -x509 -nodes -days 365 -subj /CN=test -newkey rsa:2048 \
        -keyout /etc/pki/tls/private/test.key -out /etc/pki/tls/certs/test.pem 2>/dev/null || true
    cat > /etc/nginx/nginx.conf << 'NGINX_EOF'
worker_processes 1;
events { worker_connections 64; }
http {
    access_log off;
    server {
        listen 80;
        listen 443 ssl;
        ssl_certificate /etc/pki/tls/certs/test.pem;
        ssl_certificate_key /etc/pki/tls/private/test.key;
        root /var/www/html;
    }
}
NGINX_EOF
    nginx && echo "  nginx ready"
}

setup_apache() {
    mkdir -p /var/www/html
    echo '{"ok":true}' > /var/www/html/health
    openssl req -x509 -nodes -days 365 -subj /CN=test -newkey rsa:2048 \
        -keyout /etc/pki/tls/private/test.key -out /etc/pki/tls/certs/test.pem 2>/dev/null || true
    [ -f /etc/httpd/conf.d/ssl.conf ] && mv /etc/httpd/conf.d/ssl.conf /etc/httpd/conf.d/ssl.conf.disabled 2>/dev/null || true
    cat > /etc/httpd/conf.d/test.conf << 'APACHE_EOF'
Listen 8080
<VirtualHost *:8080>
    DocumentRoot /var/www/html
</VirtualHost>
Listen 8443
<VirtualHost *:8443>
    DocumentRoot /var/www/html
    SSLEngine on
    SSLCertificateFile /etc/pki/tls/certs/test.pem
    SSLCertificateKeyFile /etc/pki/tls/private/test.key
</VirtualHost>
APACHE_EOF
    httpd && echo "  httpd ready"
}

setup_hitch_varnish() {
    mkdir -p /var/www/html
    echo '{"ok":true}' > /var/www/html/health
    openssl req -x509 -nodes -days 365 -subj /CN=test -newkey rsa:2048 \
        -keyout /etc/pki/tls/private/test.key -out /etc/pki/tls/certs/test.pem 2>/dev/null || true

    # Start simple HTTP backend
    nohup python3 -c 'import http.server, os; os.chdir("/var/www/html"); http.server.HTTPServer(("127.0.0.1", 8081), http.server.SimpleHTTPRequestHandler).serve_forever()' </dev/null >/dev/null 2>&1 &
    sleep 1

    # Varnish
    mkdir -p /etc/varnish
    cat > /etc/varnish/default.vcl << 'VARNISH_EOF'
vcl 4.1;
backend default { .host = "127.0.0.1"; .port = "8081"; }
VARNISH_EOF
    varnishd -a :80 -f /etc/varnish/default.vcl -s malloc,64m 2>/dev/null || true
    sleep 1

    # Hitch (combined PEM: key + cert)
    mkdir -p /etc/hitch
    cat /etc/pki/tls/private/test.key /etc/pki/tls/certs/test.pem > /etc/pki/tls/private/hitch.pem
    cat > /etc/hitch/hitch.conf << 'HITCH_EOF'
frontend = {
    host = "0.0.0.0"
    port = "443"
    tls = on
    pem-file = "/etc/pki/tls/private/hitch.pem"
}
backend = "[127.0.0.1]:80"
user = "nobody"
HITCH_EOF
    hitch --daemon --config=/etc/hitch/hitch.conf >/dev/null 2>&1 && echo '  hitch started' || echo '  hitch failed'
    sleep 1
    echo "  hitch+varnish ready"
}

# ── Main setup ──────────────────────────────────────────────────────

# [A] Install RPM
echo "  [A] Install RPM..."
pkill ja4ebpf 2>/dev/null || true; sleep 1
yum remove -y ja4ebpf 2>/dev/null || true
yum install -y /tmp/ja4ebpf-test.rpm 2>&1 | tail -3
[ -x /usr/sbin/ja4ebpf ] && echo "  binary OK" || { echo "  FAIL: binary not found"; exit 1; }

# [B] Configure
echo "  [B] Configure..."
mkdir -p /etc/ja4ebpf
cat > /etc/ja4ebpf/config.yml << 'CONF_EOF'
interface: eth0
ssl_lib_path: "/usr/lib64/libssl.so.3"
debug: true
clickhouse:
  dsn: "clickhouse://default:@127.0.0.1:9000/ja4_logs"
  batch_size: 50
  flush_secs: 1
correlation:
  timeout_ms: 500
  slowloris_ms: 10000
log:
  level: "debug"
  format: "text"
CONF_EOF

# [C] Start web stack
echo "  [C] Stack: $STACK..."
nginx -s stop 2>/dev/null || true
httpd -k stop 2>/dev/null || true
pkill varnishd 2>/dev/null || true
pkill hitch 2>/dev/null || true
pkill -f 'python3 -c' 2>/dev/null || true
sleep 1

case "$STACK" in
    nginx)         setup_nginx ;;
    apache)        setup_apache ;;
    hitch-varnish) setup_hitch_varnish ;;
esac

# Open firewall
firewall-cmd --add-service=http --add-service=https 2>/dev/null || true
firewall-cmd --add-port=8080/tcp --add-port=8443/tcp 2>/dev/null || true

# [D] Start ja4ebpf
echo "  [D] Start ja4ebpf..."
JA4EBPF_CONFIG=/etc/ja4ebpf/config.yml /usr/sbin/ja4ebpf > /tmp/ja4-test.log 2>&1 &
JA4PID=$!
sleep 3

if ! kill -0 $JA4PID 2>/dev/null; then
    echo "  FAIL: ja4ebpf crashed"
    cat /tmp/ja4-test.log
    exit 1
fi
echo "  PID=$JA4PID"

# Check TC ingress filter
if tc filter show dev eth0 ingress 2>/dev/null | grep -qi "bpf\|direct-action"; then
    echo "  TC: attached"
else
    echo "  WARN: TC filter not detected"
fi
SETUP_EOF

    # Replace stack placeholder
    sed -i "s/__STACK__/$STACK/" "$SETUP_SCRIPT"
    echo "$SETUP_SCRIPT"
}

# ── Test one VM×stack combination ───────────────────────────────────

test_vm_stack() {
    local VM="$1"
    local STACK="$2"
    local LABEL="$VM/$STACK"
    local START_TIME=$(date +%s)

    echo ""
    echo "── $LABEL ─────────────────────────────────────────────"

    # Check VM running
    if ! v status "$VM" 2>/dev/null | grep -q "running"; then
        echo "  SKIP: VM not running"
        echo "  SKIP: VM not running (VM off)"
        return
    fi

    # Find RPM
    local EL=$(vm_to_el "$VM")
    local RPM=$(ls -t $RPM_BASE/$EL/ja4ebpf-*.rpm | head -1)
    echo "  RPM: $(basename $RPM)"

    # Upload RPM
    if ! timeout "$UPLOAD_TIMEOUT" sh -c "cd $VM_DIR && vagrant upload $RPM /tmp/ja4ebpf-test.rpm $VM" 2>/dev/null; then
        echo "  FAIL: RPM upload timeout"
        return
    fi

    # Get VM IP
    local VM_IP=$(vssh "$VM" "ip -4 addr show eth0" | awk '/inet /{sub(/\/.*/,"",$2); print $2; exit}')
    if [ -z "$VM_IP" ]; then
        echo "  SKIP: no eth0 IP"
        return
    fi
    echo "  IP: $VM_IP"

    # Generate and upload setup script
    local SETUP_SCRIPT=$(generate_setup_script "$STACK")
    if ! timeout "$UPLOAD_TIMEOUT" sh -c "cd $VM_DIR && vagrant upload $SETUP_SCRIPT /tmp/ja4-setup.sh $VM" 2>/dev/null; then
        echo "  FAIL: setup script upload timeout"
        rm -f "$SETUP_SCRIPT"
        return
    fi
    rm -f "$SETUP_SCRIPT"

    # Execute setup script on VM via SSH
    if ! timeout "$SSH_TIMEOUT" bash -c "cd '$VM_DIR' && vagrant ssh '$VM' -- 'sudo bash /tmp/ja4-setup.sh'" 2>/dev/null; then
        echo "  FAIL: VM setup timeout/error"
        return
    fi

    # [E] Generate traffic from HOST
    echo "  [E] Traffic host→VM..."
    local HTTP_PORT HTTPS_PORT
    case "$STACK" in
        nginx)         HTTP_PORT=80;  HTTPS_PORT=443 ;;
        apache)        HTTP_PORT=8080; HTTPS_PORT=8443 ;;
        hitch-varnish) HTTP_PORT=80;  HTTPS_PORT=443 ;;
    esac

    for i in $(seq 1 3); do
        curl -sf --max-time 5 "http://$VM_IP:$HTTP_PORT/health" -o /dev/null 2>&1 && echo "  HTTP $i: OK" || echo "  HTTP $i: FAIL"
        curl -skf --max-time 5 "https://$VM_IP:$HTTPS_PORT/health" -o /dev/null 2>&1 && echo "  HTTPS $i: OK" || echo "  HTTPS $i: FAIL"
    done

    # [F] Wait for debug dump
    sleep 6

    # [G] Collect results
    echo "  [G] Results..."
    vssh "$VM" "sudo cat /tmp/ja4-test.log" > /tmp/vm-ja4-log.txt 2>/dev/null || true

    # Cleanup VM
    timeout 15 bash -c "cd '$VM_DIR' && vagrant ssh '$VM' -- 'sudo pkill ja4ebpf 2>/dev/null; sudo nginx -s stop 2>/dev/null; sudo httpd -k stop 2>/dev/null; sudo pkill varnishd 2>/dev/null; sudo pkill hitch 2>/dev/null; sudo pkill -f python3 2>/dev/null; echo cleanup_done'" 2>/dev/null > /dev/null || true

    # Parse on host side
    local LAST_DEBUG=$(grep "\[debug\] BPF:" /tmp/vm-ja4-log.txt 2>/dev/null | tail -1)
    local LAST_GO=$(grep "\[debug\] GO:" /tmp/vm-ja4-log.txt 2>/dev/null | tail -1)
    local SESSIONS=$(grep -c "session pr" /tmp/vm-ja4-log.txt 2>/dev/null || echo 0)
    local SYN_SUB=$(echo "$LAST_DEBUG" | sed -n 's/.*SYN_SUB=\([0-9]*\).*/\1/p')
    SYN_SUB=${SYN_SUB:-0}

    local ELAPSED=$(( $(date +%s) - START_TIME ))
    echo "    BPF: $LAST_DEBUG"
    echo "    GO:  $LAST_GO"
    echo "    sessions=$SESSIONS  SYN_SUB=$SYN_SUB  (${ELAPSED}s)"

    if [ "$SYN_SUB" -gt 0 ] 2>/dev/null; then
        echo "  PASS: SYN_SUB=$SYN_SUB sessions=$SESSIONS"
    else
        echo "  FAIL: SYN_SUB=0 (no TC capture)"
    fi
}

# ── Main loop ────────────────────────────────────────────────────────

for v in $VMS; do
    for s in $STACKS; do
        LABEL="$v/$s"
        TMPFILE=$(mktemp /tmp/ja4-test-XXXXXX.log)

        # Run test_vm_stack in background, capture output
        (
            test_vm_stack "$v" "$s"
        ) > "$TMPFILE" 2>&1 &
        TESTPID=$!

        # Wait with timeout
        if ! timeout --signal=TERM --kill-after=10 "$TEST_TIMEOUT" bash -c "while kill -0 $TESTPID 2>/dev/null; do sleep 1; done"; then
            kill -9 $TESTPID 2>/dev/null || true
            wait $TESTPID 2>/dev/null || true
            echo ""
            echo "── $LABEL ─────────────────────────────────────────────"
            echo "  TIMEOUT: exceeded ${TEST_TIMEOUT}s"
        else
            wait $TESTPID 2>/dev/null
        fi
        cat "$TMPFILE"

        # Parse result from output
        if grep -q "^  PASS:" "$TMPFILE" 2>/dev/null; then
            PASS=$((PASS + 1)); RESULTS+=("PASS $LABEL")
        elif grep -q "^  FAIL:" "$TMPFILE" 2>/dev/null; then
            FAIL=$((FAIL + 1)); RESULTS+=("FAIL $LABEL")
        elif grep -q "^  SKIP:" "$TMPFILE" 2>/dev/null; then
            SKIP=$((SKIP + 1)); RESULTS+=("SKIP $LABEL")
        else
            FAIL=$((FAIL + 1)); RESULTS+=("FAIL $LABEL (no result)")
        fi
        rm -f "$TMPFILE"
    done
done

# ── Summary ──────────────────────────────────────────────────────────

echo ""
echo "╔══════════════════════════════════════════════════════════════╗"
echo "║  SUMMARY: $PASS pass / $FAIL fail / $SKIP skip"
echo "╚══════════════════════════════════════════════════════════════╝"
for r in "${RESULTS[@]}"; do echo "  $r"; done

[ "$FAIL" -eq 0 ] && exit 0 || exit 1
