#!/bin/bash
# =========================================================================
# SCRIPT INSTALLAZIONE CUDA + TENSORFLOW GPU SU ALMALINUX 9.6
# VERSIONE CORRETTA - GESTISCE DRIVER NVIDIA GIÀ INSTALLATI
# =========================================================================

set -e

echo "🐧 CONFIGURAZIONE CUDA + TENSORFLOW GPU - ALMALINUX 9.6 (FIXED)"
echo "================================================================"

# Verifica sistema
echo "📋 Verifica sistema..."
cat /etc/redhat-release
uname -r

# Verifica driver NVIDIA esistenti
echo "🎮 Verifica driver NVIDIA esistenti..."
if command -v nvidia-smi &> /dev/null; then
    echo "✅ Driver NVIDIA già installati:"
    nvidia-smi --query-gpu=name,driver_version --format=csv,noheader,nounits
    NVIDIA_ALREADY_INSTALLED=true
else
    echo "❌ Driver NVIDIA non trovati"
    NVIDIA_ALREADY_INSTALLED=false
fi

# 1. AGGIORNAMENTO SISTEMA (con skip dei conflitti)
echo "🔄 Aggiornamento sistema (skip conflitti)..."
sudo dnf update -y --skip-broken

# 2. INSTALLAZIONE REPOSITORY EPEL
echo "📦 Installazione EPEL..."
sudo dnf install -y epel-release

# 3. INSTALLAZIONE STRUMENTI SVILUPPO
echo "🔧 Installazione strumenti sviluppo..."
sudo dnf groupinstall -y "Development Tools"
sudo dnf install -y kernel-devel kernel-headers gcc gcc-c++ make dkms

# 4. CONFIGURAZIONE REPOSITORY CUDA (senza reinstallare driver)
echo "🚀 Configurazione repository CUDA..."
sudo dnf config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/rhel9/x86_64/cuda-rhel9.repo

# 5. INSTALLAZIONE CUDA TOOLKIT COMPATIBILE
echo "🚀 Installazione CUDA Toolkit (compatibile con driver esistenti)..."

if [ "$NVIDIA_ALREADY_INSTALLED" = true ]; then
    echo "✅ Driver esistenti rilevati - installazione solo CUDA Toolkit"
    
    # Installa solo CUDA Toolkit senza driver
    sudo dnf install -y cuda-toolkit-12-4 --exclude="nvidia-driver*,xorg-x11-drv-nvidia*,nvidia-modprobe,nvidia-persistenced,nvidia-settings"
    
    # Oppure prova versione specifica compatibile
    if [ $? -ne 0 ]; then
        echo "⚠️ Tentativo installazione CUDA 12.2 (compatibile con driver 550)..."
        sudo dnf install -y cuda-toolkit-12-2 --exclude="nvidia-driver*,xorg-x11-drv-nvidia*,nvidia-modprobe,nvidia-persistenced,nvidia-settings"
    fi
else
    echo "❌ Driver NVIDIA non installati - installazione completa necessaria"
    # Disabilita nouveau prima
    sudo tee /etc/modprobe.d/blacklist-nouveau.conf <<EOF
blacklist nouveau
options nouveau modeset=0
EOF
    sudo dracut --force
    
    # Installazione completa
    sudo dnf install -y cuda-toolkit-12-4
fi

# 6. CONFIGURAZIONE VARIABILI AMBIENTE
echo "🌍 Configurazione variabili ambiente..."

# Trova la versione CUDA installata
CUDA_VERSION=""
if [ -d "/usr/local/cuda-12.4" ]; then
    CUDA_VERSION="12.4"
elif [ -d "/usr/local/cuda-12.2" ]; then
    CUDA_VERSION="12.2"
elif [ -d "/usr/local/cuda" ]; then
    CUDA_VERSION="$(basename $(readlink -f /usr/local/cuda) | sed 's/cuda-//')"
fi

if [ -n "$CUDA_VERSION" ]; then
    echo "✅ CUDA $CUDA_VERSION rilevato"
    
    sudo tee /etc/profile.d/cuda.sh <<EOF
export CUDA_HOME=/usr/local/cuda-$CUDA_VERSION
export PATH=\$CUDA_HOME/bin:\$PATH
export LD_LIBRARY_PATH=\$CUDA_HOME/lib64:\$LD_LIBRARY_PATH
export CUDA_PATH=\$CUDA_HOME
EOF
else
    echo "⚠️ Versione CUDA non rilevata - configurazione generica"
    sudo tee /etc/profile.d/cuda.sh <<EOF
export CUDA_HOME=/usr/local/cuda
export PATH=\$CUDA_HOME/bin:\$PATH
export LD_LIBRARY_PATH=\$CUDA_HOME/lib64:\$LD_LIBRARY_PATH
export CUDA_PATH=\$CUDA_HOME
EOF
fi

# Carica variabili ambiente
source /etc/profile.d/cuda.sh

# 7. VERIFICA INSTALLAZIONE
echo "🧪 Verifica installazione CUDA..."
if command -v nvcc &> /dev/null; then
    echo "✅ NVCC installato:"
    nvcc --version
else
    echo "❌ NVCC non trovato - problemi installazione CUDA"
fi

# 8. DOWNLOAD cuDNN (manuale)
echo "📚 Configurazione cuDNN..."
echo "⚠️  SCARICA MANUALMENTE cuDNN da: https://developer.nvidia.com/cudnn"
echo "   1. Registrati/Login su NVIDIA Developer"
echo "   2. Scarica cuDNN per CUDA $CUDA_VERSION"
echo "   3. Estrai e copia:"
echo "      tar -xzf cudnn-linux-x86_64-*-archive.tar.xz"
echo "      sudo cp cudnn-linux-x86_64-*/include/cudnn*.h /usr/local/cuda/include"
echo "      sudo cp -P cudnn-linux-x86_64-*/lib/libcudnn* /usr/local/cuda/lib64"
echo "      sudo chmod a+r /usr/local/cuda/include/cudnn*.h /usr/local/cuda/lib64/libcudnn*"

# 9. PYTHON E TENSORFLOW
echo "🐍 Configurazione Python e TensorFlow..."

# Verifica Python
python3 --version
pip3 --version

# Upgrade pip
pip3 install --upgrade pip

# Installazione TensorFlow GPU compatibile
echo "🤖 Installazione TensorFlow GPU..."

# Sceglie versione TensorFlow compatibile con CUDA
if [ "$CUDA_VERSION" = "12.4" ]; then
    pip3 install tensorflow[and-cuda]==2.17.*
elif [ "$CUDA_VERSION" = "12.2" ]; then
    pip3 install tensorflow[and-cuda]==2.16.*
else
    pip3 install tensorflow[and-cuda] # Ultima versione disponibile
fi

# 10. CREAZIONE SCRIPT TEST
echo "🧪 Creazione script test..."
cat > test_cuda_production.py <<'PYEOF'
#!/usr/bin/env python3
"""
Test configurazione CUDA per sistema DDoS v04 su AlmaLinux 9.6
"""

import tensorflow as tf
import os
import subprocess

print("🔍 TEST CUDA PRODUZIONE - ALMALINUX 9.6")
print("=" * 45)

# Info sistema
print("📋 SISTEMA:")
try:
    result = subprocess.run(['cat', '/etc/redhat-release'], capture_output=True, text=True)
    print(f"   OS: {result.stdout.strip()}")
except:
    print("   OS: Non rilevato")

# Info NVIDIA
print("\n🎮 NVIDIA:")
try:
    result = subprocess.run(['nvidia-smi', '--query-gpu=name,driver_version,memory.total', '--format=csv,noheader,nounits'], 
                          capture_output=True, text=True)
    if result.returncode == 0:
        for line in result.stdout.strip().split('\n'):
            gpu_info = line.split(', ')
            if len(gpu_info) >= 3:
                print(f"   GPU: {gpu_info[0]}")
                print(f"   Driver: {gpu_info[1]}")
                print(f"   Memory: {gpu_info[2]} MB")
    else:
        print("   nvidia-smi non disponibile")
except:
    print("   Errore verifica NVIDIA")

# Info CUDA
print(f"\n🚀 CUDA:")
try:
    result = subprocess.run(['nvcc', '--version'], capture_output=True, text=True)
    if result.returncode == 0:
        for line in result.stdout.split('\n'):
            if 'release' in line:
                print(f"   NVCC: {line.strip()}")
                break
    else:
        print("   NVCC non disponibile")
except:
    print("   NVCC non trovato")

# Info TensorFlow
print(f"\n🤖 TENSORFLOW:")
print(f"   Version: {tf.__version__}")
print(f"   CUDA built: {tf.test.is_built_with_cuda()}")

# GPU devices
gpus = tf.config.list_physical_devices('GPU')
print(f"   GPU devices: {len(gpus)}")

if gpus:
    for i, gpu in enumerate(gpus):
        print(f"   GPU {i}: {gpu}")
        
    # Test computation
    print(f"\n🧪 TEST COMPUTAZIONE:")
    try:
        with tf.device('/GPU:0'):
            # Test specifico per sistema DDoS v04
            print("   Test matrice 1000x1000...")
            start = tf.timestamp()
            a = tf.random.normal([1000, 1000])
            b = tf.random.normal([1000, 1000])
            c = tf.matmul(a, b)
            end = tf.timestamp()
            
            gpu_time = (end - start).numpy()
            print(f"   ✅ GPU time: {gpu_time:.4f}s")
            
            # Test batch processing (simula sistema v04)
            print("   Test batch DDoS v04 (176 features, 1000 samples)...")
            start = tf.timestamp()
            features = tf.random.normal([1000, 176])  # Simula feature v04
            result = tf.nn.relu(tf.matmul(features, tf.random.normal([176, 64])))
            end = tf.timestamp()
            
            batch_time = (end - start).numpy()
            throughput = 1000 / batch_time
            print(f"   ✅ Batch time: {batch_time:.4f}s")
            print(f"   ✅ Throughput: {throughput:.0f} campioni/sec")
            
    except Exception as e:
        print(f"   ❌ Errore test GPU: {e}")
else:
    print("   ❌ Nessuna GPU TensorFlow trovata")

# Test cuDNN
print(f"\n📚 CUDNN:")
try:
    cuda_build_info = tf.sysconfig.get_build_info()
    cuda_version = cuda_build_info.get('cuda_version', 'N/A')
    cudnn_version = cuda_build_info.get('cudnn_version', 'N/A')
    print(f"   CUDA version: {cuda_version}")
    print(f"   cuDNN version: {cudnn_version}")
except:
    print("   Info non disponibili")

print(f"\n🎯 STATUS:")
if gpus and tf.test.is_built_with_cuda():
    print("   ✅ SISTEMA PRONTO PER DDoS DETECTION v04 GPU")
    print("   🚀 Comandi raccomandati:")
    print("      python3 analisys_04.py --max-records 1000000 --memory-optimize")
    print("      python3 detect_multi_04.py --advanced --batch-size 2000")
else:
    print("   ⚠️ Sistema in modalità CPU - performance ridotte")

PYEOF

chmod +x test_cuda_production.py

# 11. CONFIGURAZIONE SISTEMD PER NVIDIA PERSISTENCE
echo "🔧 Configurazione NVIDIA Persistence..."
if [ "$NVIDIA_ALREADY_INSTALLED" = true ]; then
    sudo systemctl enable nvidia-persistenced 2>/dev/null || echo "nvidia-persistenced non disponibile"
    sudo systemctl start nvidia-persistenced 2>/dev/null || echo "nvidia-persistenced non avviabile"
fi

echo ""
echo "✅ INSTALLAZIONE COMPLETATA!"
echo "================================"
echo ""
echo "📋 VERIFICA IMMEDIATA:"
echo "1. Test driver: nvidia-smi"
echo "2. Test CUDA: nvcc --version"
echo "3. Test completo: python3 test_cuda_production.py"
echo ""
echo "⚠️ SE cuDNN NON È INSTALLATO:"
echo "   Scarica da: https://developer.nvidia.com/cudnn"
echo "   Segui le istruzioni mostrate sopra"
echo ""
echo "🚀 SISTEMA DDoS DETECTION v04:"
echo "   export TF_GPU_MEMORY_GROWTH=1"
echo "   export CUDA_VISIBLE_DEVICES=0"
echo "   python3 analisys_04.py --max-records 1000000"
echo ""
echo "🎯 OTTIMIZZAZIONI TESLA M60:"
echo "   - Batch size raccomandato: 1000-2000"
echo "   - Memory limit: 6GB/8GB disponibili"
echo "   - Throughput atteso: 10k+ campioni/sec" 