#!/usr/bin/env bash
# ──────────────────────────────────────────────────────────────────────
#  snmp-walk.sh — Live SNMP walk → parse → HTML viewer pipeline
#
#  Usage:
#      ./snmp-walk.sh                  # uses SNMP_TARGET from .env
#      ./snmp-walk.sh 10.0.0.1         # override target IP
#      ./snmp-walk.sh 10.0.0.1 full    # override target + walk mode
#
#  Reads configuration from .env (community, version, walk mode).
#  Produces: walks/{IP}_{TIMESTAMP}_walk.txt
#            walks/{IP}_{TIMESTAMP}_walk_monitoring.json
#            walks/nid-viewer.html
# ──────────────────────────────────────────────────────────────────────
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ENV_FILE="${SCRIPT_DIR}/.env"

# ── Load .env ────────────────────────────────────────────────────────
if [[ -f "$ENV_FILE" ]]; then
    set -a
    # shellcheck source=/dev/null
    source "$ENV_FILE"
    set +a
else
    echo "Warning: ${ENV_FILE} not found — using defaults" >&2
fi

# ── Resolve parameters (CLI overrides .env) ──────────────────────────
TARGET="${1:-${SNMP_TARGET:-}}"
WALK_MODE="${2:-${SNMP_WALK_MODE:-targeted}}"
VERSION="${SNMP_VERSION:-2c}"

if [[ -z "$TARGET" ]]; then
    echo "Error: No target IP specified."
    echo "  Set SNMP_TARGET in .env or pass as argument: $0 <ip>"
    exit 1
fi

# ── Validate prerequisites ───────────────────────────────────────────
for cmd in snmpwalk python3; do
    if ! command -v "$cmd" &>/dev/null; then
        echo "Error: '$cmd' not found. Please install it." >&2
        exit 1
    fi
done

# Prefer snmpbulkwalk (GETBULK PDUs — much faster) over snmpwalk (GETNEXT)
if command -v snmpbulkwalk &>/dev/null; then
    WALK_CMD=snmpbulkwalk
    BULK_ARGS=()  # use default -Cr10; higher values truncate on some devices
else
    WALK_CMD=snmpwalk
    BULK_ARGS=()
fi

# ── Build snmpwalk auth flags ────────────────────────────────────────
SNMP_AUTH=()
if [[ "$VERSION" == "3" ]]; then
    SNMP_AUTH+=(-v3)
    SNMP_AUTH+=(-u "${SNMP_V3_USER:?SNMP_V3_USER required for v3}")
    SNMP_AUTH+=(-l "${SNMP_V3_SEC_LEVEL:-authPriv}")
    if [[ "${SNMP_V3_SEC_LEVEL:-authPriv}" != "noAuthNoPriv" ]]; then
        SNMP_AUTH+=(-a "${SNMP_V3_AUTH_PROTO:-SHA}")
        SNMP_AUTH+=(-A "${SNMP_V3_AUTH_PASS:?SNMP_V3_AUTH_PASS required}")
    fi
    if [[ "${SNMP_V3_SEC_LEVEL:-authPriv}" == "authPriv" ]]; then
        SNMP_AUTH+=(-x "${SNMP_V3_PRIV_PROTO:-AES}")
        SNMP_AUTH+=(-X "${SNMP_V3_PRIV_PASS:?SNMP_V3_PRIV_PASS required}")
    fi
else
    SNMP_AUTH+=(-v "${VERSION}" -c "${SNMP_COMMUNITY:-public}")
fi

# ── Define OID subtrees ──────────────────────────────────────────────
# Targeted: only what the viewer/parser needs
WALK_POLICIES="${SNMP_WALK_POLICIES:-true}"

TARGETED_OIDS=(
    .1.3.6.1.2.1.1            # System (sysDescr, sysName, sysUpTime, …)
    .1.3.6.1.2.1.2            # IF-MIB (interface table)
    .1.3.6.1.2.1.4            # IP-MIB (addresses, routes)
    .1.3.6.1.2.1.31           # IF-MIB extensions (ifName, ifAlias, 64-bit counters)
    .1.3.6.1.2.1.55           # IPv6-MIB
    .1.3.111.2.802.1.1.13     # LLDP-MIB (neighbors, stats)
    .1.3.6.1.4.1.22420.1.1    # ACD-DESC-MIB (device identity, connectors, sensors)
    .1.3.6.1.4.1.22420.2.1    # ACD-ALARM-MIB
    .1.3.6.1.4.1.22420.2.2    # ACD-FILTER-MIB
    .1.3.6.1.4.1.22420.2.4    # ACD-SFP-MIB (transceiver info/diag)
    .1.3.6.1.4.1.22420.2.6    # ACD-REGULATOR-MIB
    .1.3.6.1.4.1.22420.2.8    # ACD-SMAP-MIB (CoS profiles)
    .1.3.6.1.4.1.22420.2.9    # ACD-PORT-MIB (port config/status)
)

if [[ "$WALK_POLICIES" == "true" ]]; then
    TARGETED_OIDS+=(.1.3.6.1.4.1.22420.2.3)  # ACD-POLICY-MIB (~73% of all OIDs)
fi

# ── Prepare output paths ─────────────────────────────────────────────
TIMESTAMP="$(date +%Y-%m-%d_%H-%M-%S)"
SAFE_IP="${TARGET//./-}"
WALKS_DIR="${SCRIPT_DIR}/walks"
WALK_FILE="${WALKS_DIR}/${SAFE_IP}_${TIMESTAMP}_walk.txt"
ERROR_FILE="${WALKS_DIR}/${SAFE_IP}_${TIMESTAMP}_errors.txt"

mkdir -p "$WALKS_DIR"

# ── Execute SNMP walk ─────────────────────────────────────────────────
echo "═══════════════════════════════════════════════════════"
echo "  SNMP NID Viewer — Live Walk"
echo "═══════════════════════════════════════════════════════"
echo "  Target:    ${TARGET}"
echo "  Version:   SNMPv${VERSION}"
echo "  Mode:      ${WALK_MODE}"
echo "  Walker:    ${WALK_CMD}${BULK_ARGS:+ (max-rep=${BULK_ARGS[1]#-Cr})}"
echo "  Output:    ${WALK_FILE}"
echo "═══════════════════════════════════════════════════════"
echo ""

WALK_START="$(date +%s)"

if [[ "$WALK_MODE" == "full" ]]; then
    echo "[1/3] Walking full OID tree (.1) ..."
    "$WALK_CMD" -On -OQ "${BULK_ARGS[@]}" "${SNMP_AUTH[@]}" "$TARGET" .1 \
        > "$WALK_FILE" 2> "$ERROR_FILE" || true
else
    echo "[1/3] Walking ${#TARGETED_OIDS[@]} targeted subtrees ..."
    : > "$WALK_FILE"
    : > "$ERROR_FILE"
    for oid in "${TARGETED_OIDS[@]}"; do
        echo "       ↳ ${oid}"
        "$WALK_CMD" -On -OQ "${BULK_ARGS[@]}" "${SNMP_AUTH[@]}" "$TARGET" "$oid" \
            >> "$WALK_FILE" 2>> "$ERROR_FILE" || true
    done
fi

WALK_END="$(date +%s)"
WALK_LINES="$(wc -l < "$WALK_FILE")"
WALK_SECS=$(( WALK_END - WALK_START ))
echo "  ✓ Walk complete: ${WALK_LINES} lines in ${WALK_SECS}s"

# Remove empty error file
if [[ ! -s "$ERROR_FILE" ]]; then
    rm -f "$ERROR_FILE"
fi

if [[ "$WALK_LINES" -eq 0 ]]; then
    echo ""
    echo "Error: Walk returned no data. Check:"
    echo "  - Device reachability (ping ${TARGET})"
    echo "  - SNMP community/credentials in .env"
    echo "  - Firewall rules (UDP 161)"
    [[ -s "$ERROR_FILE" ]] && echo "" && cat "$ERROR_FILE"
    exit 1
fi

# ── Parse walk → monitoring JSON ──────────────────────────────────────
echo ""
echo "[2/3] Parsing walk data ..."
python3 "${SCRIPT_DIR}/snmp-parse.py" "$WALK_FILE"

MONITORING_JSON="${WALK_FILE%.txt}_monitoring.json"
if [[ ! -f "$MONITORING_JSON" ]]; then
    echo "Error: snmp-parse.py did not produce ${MONITORING_JSON}" >&2
    exit 1
fi
echo "  ✓ Monitoring JSON: ${MONITORING_JSON}"

# ── Build HTML viewer ─────────────────────────────────────────────────
echo ""
echo "[3/3] Building HTML viewer ..."
python3 "${SCRIPT_DIR}/build_nid_viewer.py" "$MONITORING_JSON"
echo "  ✓ Viewer: ${WALKS_DIR}/nid-viewer.html"

# ── Summary ───────────────────────────────────────────────────────────
echo ""
echo "═══════════════════════════════════════════════════════"
echo "  Done! Open walks/nid-viewer.html in a browser."
echo "═══════════════════════════════════════════════════════"
