#!/usr/bin/env bash
# ============================================================
#  Ethereum on ARM - System Diagnostic Script 
#  Checks hardware, network, system, and Ethereum client status.
# ============================================================

set -euo pipefail

# --- Default settings ---
USE_COLORS=true
SHOW_SUMMARY=true
SHOW_LOGS=false
LOG_FILE="/var/log/eoa_check.log"

# --- Redirect output to console and log file ---
exec > >(tee -a "$LOG_FILE") 2>&1

# --- Check for root privileges ---
if [ "$(id -u)" != "0" ]; then
    echo -e "Error: You must be root to run this script. Please use sudo."
    exit 1
fi

# --- Parse command-line options ---
#  -n : disable color
#  -s : skip summary
#  -l : show extended logs (processes, syslog, dmesg)
while getopts "nsl" opt; do
    case ${opt} in
        n) USE_COLORS=false ;;
        s) SHOW_SUMMARY=false ;;
        l) SHOW_LOGS=true ;;
        \?) echo "Invalid option: -$OPTARG" >&2; exit 1 ;;
    esac
done

# --- Color configuration ---
if [ "$USE_COLORS" = true ]; then
    RED='\033[0;91m'; GREEN='\033[0;92m'; ORANGE='\033[0;33m'
    YELLOW='\033[0;93m'; BLUE='\033[0;94m'; MAGENTA='\033[0;95m'
    BOLD='\033[1m'; NC='\033[0m'
else
    RED=''; GREEN=''; ORANGE=''; YELLOW=''; BLUE=''; MAGENTA=''; BOLD=''; NC=''
fi

# --- Display summary before running ---
if [ "$SHOW_SUMMARY" = true ]; then
    echo -e "${BOLD}This script will check your system in the following areas:${NC}"
    echo -e "${BLUE}1. Hardware:${NC} Board model, RAM, disks, temperature, CPU"
    echo -e "${BLUE}2. Network:${NC} Local/public IP, open ports, speed test"
    echo -e "${BLUE}3. System:${NC} OS, kernel, firewall, updates, EOA packages"
    echo -e "${BLUE}4. Ethereum:${NC} User, clients, JWT file, communication ports"
    echo -e "${BLUE}5. Logs:${NC} Largest log files, active processes, system logs"
    echo
    read -rp "Do you want to continue? (y/n) " -n 1 -r; echo
    [[ ! $REPLY =~ ^[Yy]$ ]] && exit 1
fi

# --- Helper functions ---
section() {
    local title=$1
    local line
    line=$(printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' "=")
    echo -e "\n${BOLD}${MAGENTA}$line${NC}"
    echo -e "${BOLD}${MAGENTA}# ${title}${NC}"
    echo -e "${BOLD}${MAGENTA}$line${NC}"
}
separator() { printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' -; }

# ============================================================
#  STEP 1: DEPENDENCY CHECK
# ============================================================
echo -e "${BOLD}Checking required dependencies...${NC}"

declare -A required_packages=(
    [tr]="coreutils" [free]="procps" [awk]="gawk" [bc]="bc"
    [lscpu]="util-linux" [uptime]="procps" [df]="coreutils"
    [ip]="iproute2" [ufw]="ufw" [lsb_release]="lsb-release"
    [uname]="coreutils" [du]="coreutils" [find]="findutils"
    [apt-get]="apt" [id]="coreutils" [systemctl]="systemd"
    [nc]="netcat-openbsd" [curl]="curl" [jq]="jq"
    [ss]="iproute2" [numfmt]="coreutils" [speedtest-cli]="speedtest-cli"
)

packages_to_install=()
for cmd in "${!required_packages[@]}"; do
    if ! command -v "$cmd" &>/dev/null; then
        pkg="${required_packages[$cmd]}"
        [[ ! " ${packages_to_install[*]} " =~ " ${pkg} " ]] && packages_to_install+=("$pkg")
    fi
done

if [ ${#packages_to_install[@]} -gt 0 ]; then
    echo -e "${ORANGE}Missing packages detected: ${packages_to_install[*]}${NC}"
    apt-get update -y && apt-get install -y "${packages_to_install[@]}"
fi
echo -e "${GREEN}All dependencies are installed.${NC}"

# ============================================================
#  SECTION 1: HARDWARE INFORMATION
# ============================================================
section "HARDWARE"

separator
echo -e "${BOLD}${BLUE}BOARD MODEL${NC}"
BOARD_MODEL=$(cat /sys/firmware/devicetree/base/model 2>/dev/null | tr -d '\0' || true)
[ -z "$BOARD_MODEL" ] && BOARD_MODEL=$(hostnamectl | grep "Model" | cut -d: -f2- | xargs)
[ -z "$BOARD_MODEL" ] && BOARD_MODEL="Unknown"
echo -e "Model: ${YELLOW}$BOARD_MODEL${NC}"

separator
echo -e "${BOLD}${BLUE}RAM${NC}"
TOTAL_RAM_GB=$(free -g | awk '/^Mem:/{print $2}')
[[ "$TOTAL_RAM_GB" =~ ^[0-9]+$ ]] || TOTAL_RAM_GB=0
if [ "$TOTAL_RAM_GB" -lt 8 ]; then
    echo -e "RAM check ${RED}FAIL${NC} (less than 8 GB)"
elif [ "$TOTAL_RAM_GB" -eq 8 ]; then
    echo -e "RAM check ${ORANGE}WARNING${NC} (exactly 8 GB)"
else
    echo -e "RAM check ${GREEN}PASS${NC} (16 GB or more)"
fi

separator
echo -e "${BOLD}${BLUE}DISKS${NC}"
NVME_DISK=false; USB_DISK=false
[ -e "/dev/nvme0n1" ] && NVME_DISK=true && NVME_DISK_MODEL=$(tr </sys/class/block/nvme0n1/device/model -d '\0' 2>/dev/null || echo "Unknown")
[ -e "/dev/sda" ] && USB_DISK=true && USB_DISK_MODEL=$(tr </sys/class/block/sda/device/model -d '\0' 2>/dev/null || echo "Unknown")
if $NVME_DISK || $USB_DISK; then
    echo -e "Disk check ${GREEN}PASS${NC} (External or SSD detected)"
else
    echo -e "${RED}No external or SSD disk detected${NC}"
fi
$NVME_DISK && echo -e "NVMe Model: ${YELLOW}$NVME_DISK_MODEL${NC}"
$USB_DISK && echo -e "USB Model: ${YELLOW}$USB_DISK_MODEL${NC}"
swapon -s || true

separator
echo -e "${BOLD}${BLUE}TEMPERATURE${NC}"
TEMP_RAW=$(cat /sys/class/thermal/thermal_zone0/temp 2>/dev/null || echo "0")
if [[ "$TEMP_RAW" =~ ^[0-9]+$ ]]; then
    printf "Board Temp: ${YELLOW}%.2f°C${NC}\n" "$(echo "$TEMP_RAW / 1000" | bc -l)"
else
    echo -e "Board Temp: ${RED}Unknown${NC}"
fi

separator
echo -e "${BOLD}${BLUE}CPU INFORMATION${NC}"
CPU_MODEL=$(lscpu | grep "Model name" | sed 's/Model name:[ \t]*//')
CPU_CORES=$(lscpu | awk '/^CPU\(s\):/{print $2}')
LOAD_AVG=$(uptime | awk -F'[a-z]:' '{print $2}')
UPTIME=$(uptime -p)
echo -e "Model: ${YELLOW}$CPU_MODEL${NC}"
echo -e "Cores: ${YELLOW}$CPU_CORES${NC}"
echo -e "Load Avg: ${YELLOW}$LOAD_AVG${NC}"
echo -e "Uptime: ${YELLOW}$UPTIME${NC}"

separator
echo -e "${BOLD}${BLUE}DISK USAGE${NC}"
df -h --output=source,fstype,size,used,avail,pcent,target

separator
echo -e "${BOLD}${BLUE}USB DEVICES${NC}"
if command -v lsusb >/dev/null; then
    lsusb || echo "No USB devices detected or lsusb failed."
else
    echo "lsusb not installed"
fi

separator
echo -e "${BOLD}${BLUE}LOADED KERNEL MODULES${NC}"
lsmod | head -n 50
echo -e "${YELLOW}(showing first 50 entries)${NC}"

separator
echo -e "${BOLD}${BLUE}PROCESS INFORMATION${NC}"
total_procs=$(ps -e --no-headers | wc -l)
echo -e "Total running processes: ${YELLOW}${total_procs}${NC}"
ps -eo pid,ppid,comm,%cpu,%mem --sort=-%cpu | head -n 10 | \
awk -v bold="$BOLD" -v nc="$NC" 'NR==1 { printf bold "%-6s %-6s %-30s %-6s %-6s\n", "PID", "PPID", "COMMAND", "%CPU", "%MEM" nc; next }
{ printf "%-6s %-6s %-30s %-6s %-6s\n", $1, $2, $3, $4, $5 }'
echo -e "${YELLOW}(top 10 processes by CPU)${NC}"

separator
echo -e "${BOLD}${BLUE}INTERRUPTS (TOP 30)${NC}"
head -n 1 /proc/interrupts
grep -v "^CPU" /proc/interrupts | head -n 30 || echo "Interrupt data not available."

# ============================================================
#  SECTION 2: NETWORK INFORMATION
# ============================================================
section "NETWORK"

separator
echo -e "${BOLD}${BLUE}LOCAL NETWORK CONFIGURATION${NC}"
ip -4 addr show | grep inet
echo
ip route

separator
echo -e "${BOLD}${BLUE}PUBLIC NETWORK INFO${NC}"
ifconfig_data=$(curl -s ifconfig.co/json || echo "{}")
ip_address=$(echo "$ifconfig_data" | jq -r '.ip // empty')
asn=$(echo "$ifconfig_data" | jq -r '.asn // empty')
asn_org=$(echo "$ifconfig_data" | jq -r '.asn_org // empty')
echo -e "Public IP: ${YELLOW}${ip_address:-Unknown}${NC}"
echo -e "ASN: ${YELLOW}${asn:-Unknown}${NC}"
echo -e "Network Provider: ${YELLOW}${asn_org:-Unknown}${NC}"

separator
echo -e "${BOLD}${BLUE}FORWARDED PORTS${NC}"
for port in 30303 9000; do
    if nc -4 -z -w3 "$ip_address" $port 2>/dev/null; then
        echo -e "Port $port ${GREEN}open${NC}"
    elif nc -6 -z -w3 "$ip_address" $port 2>/dev/null; then
        echo -e "Port $port ${GREEN}open (IPv6)${NC}"
    else
        echo -e "Port $port ${RED}closed${NC}"
    fi
done

separator
echo -e "${BOLD}${BLUE}INTERNET SPEED TEST${NC}"
if command -v speedtest-cli >/dev/null; then
    output=$(speedtest-cli --csv 2>&1 || true)
    if [[ -n "$output" ]]; then
        download_speed=$(echo "$output" | awk -F , '{print $7}')
        upload_speed=$(echo "$output" | awk -F , '{print $8}')
        echo -e "Download: ${YELLOW}$(numfmt --to=iec-i <<<"$download_speed")B/s${NC}"
        echo -e "Upload:   ${YELLOW}$(numfmt --to=iec-i <<<"$upload_speed")B/s${NC}"
    else
        echo -e "${RED}Speedtest failed${NC}"
    fi
else
    echo -e "${ORANGE}speedtest-cli not available, testing with curl...${NC}"
    curl -o /dev/null -s -w "Download speed: %{speed_download} bytes/sec\n" https://speed.hetzner.de/10MB.bin
fi

# ============================================================
#  SECTION 3: SYSTEM INFORMATION
# ============================================================
section "SYSTEM & OTHER SOFTWARE"

separator
echo -e "${BOLD}${BLUE}OS AND KERNEL${NC}"
lsb_release -a 2>/dev/null || cat /etc/os-release
echo -e "Kernel: ${YELLOW}$(uname -r)${NC}"
echo -e "Architecture: ${YELLOW}$(uname -m)${NC}"

separator
echo -e "${BOLD}${BLUE}SECURITY STATUS${NC}"
ufw status verbose 2>/dev/null || echo "ufw not active"
if command -v aa-status >/dev/null; then aa-status || true; else echo "AppArmor not installed"; fi

separator
echo -e "${BOLD}${BLUE}PENDING SYSTEM UPDATES${NC}"
apt-get update -qq
apt-get --just-print upgrade 2>/dev/null | grep -Eo 'Inst [^ ]+' || echo "No pending updates"

separator
echo -e "${BOLD}${BLUE}INSTALLED EOA PACKAGES${NC}"
dpkg -l | grep -E '(^ii\s)?(ethereumonarm|eoa-|ethrex(-l2)?|reth|geth|besu|erigon(-externalcl)?|nethermind|lighthouse|lodestar|nimbus|prysm|teku|grandine|charon|obol)' || echo "No EOA packages found"

separator
echo -e "${BOLD}${BLUE}LISTENING PORTS${NC}"
ss -tunlp | awk -v bold="$BOLD" -v nc="$NC" 'BEGIN{print bold"Proto\tLocal Address\t\tPID/Program"nc}{printf "%-6s\t%-22s\t%s\n",$1,$5,$7}'

# ============================================================
#  SECTION 4: ETHEREUM CLIENT STATUS
# ============================================================
section "ETHEREUM SOFTWARE"


separator
echo -e "${BOLD}${BLUE}ETHEREUM CLIENT DETECTION${NC}"

# --- Configurable arrays ---
EXECUTION_CLIENTS=(geth erigon erigon-externalcl nethermind besu reth ethrex nimbus-execution)
CONSENSUS_CLIENTS=(lighthouse prysm teku nimbus lodestar grandine)
VALIDATOR_SUFFIX="validator"

# List of active testnets — update here as networks evolve
# Example: TESTNETS=(sepolia hoodi gnosis devnet8)
TESTNETS=(sepolia hoodi gnosis)

# Track detected clients
execution_found=false
consensus_found=false

check_service() {
    local svc="$1"
    if systemctl is-active --quiet "$svc"; then
        echo -e "${GREEN}$svc${NC} active"
        return 0
    fi
    return 1
}

# ---- Execution Layer ----
echo -e "${BOLD}Execution layer:${NC}"
for base in "${EXECUTION_CLIENTS[@]}"; do
    # Check base service
    check_service "$base" && execution_found=true
    # Check all testnet variants
    for net in "${TESTNETS[@]}"; do
        check_service "${base}-${net}" && execution_found=true
    done
done

# ---- Consensus Layer ----
echo
echo -e "${BOLD}Consensus layer:${NC}"
for base in "${CONSENSUS_CLIENTS[@]}"; do
    # Beacon + MEV
    for suffix in "beacon" "beacon-mev"; do
        check_service "${base}-${suffix}" && consensus_found=true
        for net in "${TESTNETS[@]}"; do
            check_service "${base}-${suffix}-${net}" && consensus_found=true
        done
    done
    # Validator + MEV
    for suffix in "$VALIDATOR_SUFFIX" "$VALIDATOR_SUFFIX-mev"; do
        check_service "${base}-${suffix}" && consensus_found=true
        for net in "${TESTNETS[@]}"; do
            check_service "${base}-${suffix}-${net}" && consensus_found=true
        done
    done
done

echo
if ! $execution_found; then
    echo -e "${RED}No execution client detected${NC}"
fi
if ! $consensus_found; then
    echo -e "${RED}No consensus client detected${NC}"
fi

separator
jwtsecret_file="/etc/ethereum/jwtsecret"
if test -s "$jwtsecret_file"; then
    echo -e "JWT file ${GREEN}OK${NC}"
else
    echo -e "${RED}Missing or empty JWT file${NC}"
fi

separator
if nc -z localhost 8545; then
    echo -e "Port 8545 ${GREEN}open${NC}"
else
    echo -e "${RED}Port 8545 closed (EL and CL may not communicate)${NC}"
fi

# ============================================================
#  SECTION 5: LOG INFORMATION
# ============================================================
section "LOGS"

separator
echo -e "${BOLD}${BLUE}TOP 10 LARGEST LOG FILES${NC}"
find /var/log -type f -exec du -h --apparent-size {} + 2>/dev/null | sort -hr | head -n 10

if [ "$SHOW_LOGS" = true ]; then
    separator
    echo -e "${BOLD}${BLUE}TOP PROCESSES BY CPU USAGE${NC}"
    ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%cpu | head -n 20 | awk -v bold="$BOLD" -v nc="$NC" '
        NR==1 { printf bold "%-8s %-8s %-50s %-6s %-6s\n", "PID", "PPID", "COMMAND", "%MEM", "%CPU" nc; next }
        { printf "%-8s %-8s %-50s %-6s %-6s\n", $1, $2, $3, $4, $5 }
    '

    separator
    echo -e "${BOLD}${BLUE}SYSLOG (LAST 50 LINES)${NC}"
    tail -n 50 /var/log/syslog || true

    separator
    echo -e "${BOLD}${BLUE}DMESG (LAST 50 LINES)${NC}"
    dmesg -T | tail -n 50 || true
fi

echo -e "${GREEN}System check completed successfully.${NC}"
echo -e "Full log saved to: ${YELLOW}$LOG_FILE${NC}"
exit 0