#!/bin/bash

# --- PREREQUISITE CHECK ---
check_prerequisites() {
    for tool in fio jq bc sysbench curl pigz; do
        if ! command -v "$tool" &> /dev/null; then 
            echo "Error: $tool missing. Install with: sudo apt install $tool"
			echo "apt install fio jq bc sysbench curl pigz"
            exit 1
        fi
    done
}

# --- SYSTEM INFORMATION ---
show_system_info() {
    # System Info Config
    local PROC_NAME=$(grep -m1 "model name" /proc/cpuinfo | cut -d: -f2 | sed 's/^[ \t]*//')
    local CORES=$(grep -c ^processor /proc/cpuinfo)
	local FREQ=$(grep -m1 "cpu MHz" /proc/cpuinfo | cut -d: -f2 | sed 's/^[ \t]*//')
    local RAM=$(free -h | awk '/^Mem:/ {print $2}')
    local DISTRO=$(grep "PRETTY_NAME" /etc/os-release | cut -d= -f2 | tr -d '"')
    local UPTIME=$(uptime -p)
    # CPU Steal: Checks if the hypervisor is 'stealing' your cycles (Noisy Neighbor check)
    local STEAL=$(top -bn1 | grep "Cpu(s)" | awk '{print $16}') 
    local KERNEL=$(uname -r)
    local VM_TYPE=$(systemd-detect-virt | tr '[:lower:]' '[:upper:]' 2>/dev/null || echo "UNKNOWN")

    grep -q "aes" /proc/cpuinfo && AES="[OK]" || AES="[NO]"
    grep -E -q "vmx|svm" /proc/cpuinfo && VIRT="[OK]" || VIRT="[NO]"

    echo "Basic System Information:"
    echo "---------------------------------"
    echo "Processor  : $PROC_NAME"
    echo "CPU cores  : $CORES @ $FREQ MHz"
    echo "Uptime     : $UPTIME"
    echo "CPU Steal  : $STEAL% (Target: <5.0% is healthy)"
    echo "AES-NI     : $AES"
    echo "VM-x/AMD-V : $VIRT"
    echo "RAM        : $RAM"
    echo "Distro     : $DISTRO"
    echo "Kernel     : $KERNEL"
    echo "VM Type    : $VM_TYPE"
    echo ""
}

# --- CPU & MEMORY ---
run_cpu_mem_test() {
    echo "CPU & Memory Performance:"
    echo "---------------------------------"
    local ST_SCORE=$(sysbench cpu --cpu-max-prime=20000 run | grep "events per second:" | awk '{print $4}')
    local MT_SCORE=$(sysbench cpu --cpu-max-prime=20000 --threads=$(nproc) run | grep "events per second:" | awk '{print $4}')
    local MEM_SCORE=$(sysbench memory --memory-total-size=10G run | grep -oE "[0-9.]+ MiB/sec")

    echo "CPU Single Thread: $ST_SCORE (Target: >1500)"
    echo "CPU Multi Thread : $MT_SCORE"
    echo "Memory Speed     : $MEM_SCORE (Target: >10000 MiB/sec)"
    echo ""
}

# --- NETWORK (CURL + PING) ---
run_network_test() {
    # Network Config
    local LOCATIONS=(
        "Clouvider|London, UK|lon.speedtest.clouvider.net|https://lon.speedtest.clouvider.net/backend/garbage.php?ckSize=100"
        "Eranium|Amsterdam, NL|ams.speedtest.clouvider.net|https://ams.speedtest.clouvider.net/backend/garbage.php?ckSize=100"
        "Hetzner|Frankfurt, DE|fsn1-speed.hetzner.com|https://fsn1-speed.hetzner.com/100MB.bin"
        "SuperHosting|Sofia, BG|www.superhosting.bg|https://www.superhosting.bg/"
    )

    echo "Network Performance (CURL + PING):"
    echo "--------------------------------------------------------------------------------"
    printf "%-12s | %-15s | %-15s | %-12s\n" "Provider" "Location" "Recv Speed" "Ping"
    echo "--------------------------------------------------------------------------------"

    for entry in "${LOCATIONS[@]}"; do
        IFS="|" read -r prov loc host url <<< "$entry"
        local ping_res=$(ping -c 4 -q "$host" 2>/dev/null | tail -1 | awk -F '/' '{print $5}')
        [[ -z "$ping_res" ]] && ping_res="TIMEOUT" || ping_res="${ping_res} ms"
        
        local speed_res=$(curl -m 15 -Lo /dev/null -skw "%{speed_download}\n" "$url")
        local speed_gbps=$(echo "scale=2; $speed_res * 8 / 1000000" | bc -l)

        printf "%-12s | %-15s | %-15s | %-12s\n" "$prov" "$loc" "$speed_gbps Mbps" "$ping_res"
    done
    echo ""
}

# --- STORAGE (FIO) ---
run_storage_test() {
    # Storage Config
    local TEST_FILE="fio_test_file"
    local BLOCK_SIZES=("4k" "1m")
    local PATTERNS=("randread" "randwrite")
    local RUNTIME=10

    echo "Storage Performance (fio):"
    echo "--------------------------------------------------------------------------------"
    printf "%-12s | %-10s | %-12s | %-12s | %-12s\n" "Pattern" "BS" "IOPS" "MB/s" "Lat (us)"
    echo "--------------------------------------------------------------------------------"

    for bs in "${BLOCK_SIZES[@]}"; do
        for rw in "${PATTERNS[@]}"; do
            local res=$(fio --name=bench --filename=$TEST_FILE --size=1G \
                --direct=1 --rw=$rw --bs=$bs --ioengine=libaio --runtime=$RUNTIME \
                --group_reporting --output-format=json --time_based 2>/dev/null)

            local key=$([[ "$rw" == *"read"* ]] && echo "read" || echo "write")
            local iops=$(echo "$res" | jq -r ".jobs[0].$key.iops")
            local bw_mib=$(echo "scale=2; $(echo "$res" | jq -r ".jobs[0].$key.bw") / 1024" | bc)
            local lat_us=$(echo "scale=2; $(echo "$res" | jq -r ".jobs[0].$key.lat_ns.mean") / 1000" | bc)

            printf "%-12s | %-10s | %-12s | %-12s | %-12s\n" "$rw" "$bs" "$(printf "%.0f" "$iops")" "$bw_mib" "$lat_us"
        done
    done
    rm -f $TEST_FILE
    echo "--------------------------------------------------------------------------------"
	echo "4k Target: >5k IOPS for Web/DB. 1m Target: >500 MB/s for SSD, >1500 MB/s for NVMe."
	echo ""
}

run_dd_test() {

	local RAM_FILE="/dev/shm/memtest1"
	local DISK_FILE="disktest1"
	
	#CPU:
	local cpu_md5=$((dd if=/dev/zero bs=1M count=1k | md5sum 1>/dev/null) 2>&1 | grep copied | awk '{ print $(NF-1) " " $(NF)}')
	local cpu_gzip=$((dd if=/dev/zero bs=1M count=1k | gzip 1>/dev/null) 2>&1 | grep copied | awk '{ print $(NF-1) " " $(NF)}')
	local cpu_pigz=$((dd if=/dev/zero bs=1M count=1k | pigz 1>/dev/null) 2>&1 | grep copied | awk '{ print $(NF-1) " " $(NF)}')
	printf "%-12s | %-12s | %-12s| %-12s\n" "CPU" "md5" "gzip" "pigz"
	printf "%-12s | %-12s | %-12s| %-12s\n" "bs=1Mx1k" "$cpu_md5" "$cpu_gzip" "$cpu_pigz"
	

	#RAM:
	local ram4k_write=$(dd if=/dev/zero of=$RAM_FILE bs=4k count=1k 2>&1 | grep copied | awk '{ print $(NF-1) " " $(NF)}')
	local ram4k_read=$(dd if=$RAM_FILE of=/dev/null bs=4k count=1k 2>&1 | grep copied | awk '{ print $(NF-1) " " $(NF)}')
	local ram1M_write=$(dd if=/dev/zero of=$RAM_FILE bs=1M count=64 2>&1 | grep copied | awk '{ print $(NF-1) " " $(NF)}')
	local ram1M_read=$(dd if=$RAM_FILE of=/dev/null bs=1M count=64 2>&1 | grep copied | awk '{ print $(NF-1) " " $(NF)}')
	rm -f $RAM_FILE

	#DISK:
	local disk4k_write=$(dd if=/dev/zero of=$DISK_FILE bs=4k count=1k oflag=direct 2>&1 | grep copied | awk '{ print $(NF-1) " " $(NF)}')
	local disk4k_read=$(dd if=$DISK_FILE of=/dev/null bs=4k count=1k iflag=direct 2>&1 | grep copied | awk '{ print $(NF-1) " " $(NF)}')
	local disk1M_write=$(dd if=/dev/zero of=$DISK_FILE bs=1M count=64 oflag=direct 2>&1 | grep copied | awk '{ print $(NF-1) " " $(NF)}')
	local disk1M_read=$(dd if=$DISK_FILE of=/dev/null bs=1M count=64 iflag=direct 2>&1 | grep copied | awk '{ print $(NF-1) " " $(NF)}')
	rm -f $DISK_FILE

	echo "dd /dev/zero Test"
	printf "%-12s | %-12s | %-12s\n" "TEST" "READ" "WRITE"
	printf "%-12s | %-12s | %-12s\n" " RAM 4k" "$ram4k_read" "$ram4k_write"
	echo ""
	printf "%-12s | %-12s | %-12s\n" " RAM 1M" "$ram1M_read" "$ram1M_write"
	printf "%-12s | %-12s | %-12s\n" "DISK 4k" "$disk4k_read" "$disk4k_write"
	printf "%-12s | %-12s | %-12s\n" "DISK 1M" "$disk1M_read" "$disk1M_write"
	echo ""
}

# --- EXECUTION ---
check_prerequisites
show_system_info
run_cpu_mem_test
run_dd_test
run_storage_test
run_network_test

