#!/bin/bash
#
# Bash script for upgrading Nagios Network Analyzer
# Copyright 2014-2025 Nagios Enterprises, LLC. All Rights reserved.
#
# Upgrade Nagios Network Analyzer
#

BASE_DIR=$(dirname $(readlink -e "$0"))
cd "$BASE_DIR"
. ./libinstall.sh

PROD_DIR="/var/www/html/nagiosna"
BACKEND_DIR="/usr/local/nagiosna"
SCRIPTS_DIR="$BACKEND_DIR/scripts/"
NAVERSION_FILE="$PROD_DIR/naversion"
ARTISAN="$PROD_DIR/artisan"

set -a
source <(grep -E '^(DB_HOST|DB_USERNAME|DB_PASSWORD|DB_DATABASE)=' "$PROD_DIR/.env")
set +a
export MYSQL_PWD="$DB_PASSWORD"

if [[ "$distro" == "Ubuntu" || "$distro" == "Debian" ]]; then
    SUPERVISOR_CONFIG="/etc/supervisor/supervisord.conf"
else
    SUPERVISOR_CONFIG="/etc/supervisord.conf"
fi

if [ "x$INTERACTIVE" = "x" ]; then
    export INTERACTIVE="True"
fi

# Ensure the script is run as root
if [ "$UID" != 0 ] ; then
    echo_c "ERROR: This script must be run as root!" "$RED"
    exit 1
fi

upgrade_help() {
    cat <<-EOF

        Nagios Network Analyzer Upgrade Script
        Copyright 2025-, Nagios Enterprises LLC.
        License:
            Nagios Software License <http://assets.nagios.com/licenses/nagios_software_license.txt>

        Usage: ./upgrade [options...]

        Options:
            -h | --help
                Display this help text
            -n | --non-interactive
                Assume defaults for all questions (for scripted installs)
EOF
}

# Parse command line arguments
while [ -n "$1" ]; do
    case "$1" in
        -h | --help)
            upgrade_help
            exit 0
            ;;
        -n | --non-interactive)
            export INTERACTIVE="False"
            ;;
        *)
            echo "Unknown option:  $1"
            upgrade_help
            exit 1
            ;;
    esac
    shift
done

# Restart the upgrade
if [ -t 1 ]; then
    $0 2>&1 | tee >(sed -r 's/\x1B\[[0-9;]*m//g' >> "upgrade.log")
    exit 0
fi

# Interactive warning and confirmation unless -n was provided
if [ "$INTERACTIVE" = "True" ]; then
    echo_c "IMPORTANT: Before upgrading, verify you have a valid system backup of Nagios Network Analyzer before continuing! \
More information about backing up and restoring Nagios Network Analyzer can be found here: \
https://assets.nagios.com/downloads/nagios-network-analyzer/docs/Backing-Up-and-Restoring-NNA-2026.pdf" "$ORANGE" >&2
    echo
    echo_c "Are you sure you want to continue? [y/N]" "$GREEN"
    read res

    if [ "$res" = "y" -o "$res" = "Y" ]; then
        echo "Proceeding with upgrade..."
    else
        echo "Upgrade cancelled"
        exit 0
    fi
fi

# Get the old version
if [ ! -f "$NAVERSION_FILE" ]; then
    echo_c "ERROR: Could not determine currently installed version of Nagios Network Analyzer!" "$RED"
    exit 1
fi
OLD_VERSION="$(grep '^VERSION=' "$NAVERSION_FILE" | cut -d '=' -f2)"
old_version_full="$(grep '^full=' "$NAVERSION_FILE" | cut -d '=' -f2)"
new_version_full="$(grep '^full=' "$BASE_DIR/nagiosna/naversion" | cut -d '=' -f2)"

# Print upgrade header
echo
echo
echo "Upgrading Nagios Network Analyzer"
echo "================================="
echo "DATE: $(date)"
echo
echo "DISTRO INFO:"
echo "$distro"
echo "$version"
echo "$architecture"
echo
echo "Upgrading from $old_version_full to $new_version_full"
echo "================================="
echo

#### UPGRADE PREREQUISITES ####

# Verify the old version is at least 2026R1
if [ "$OLD_VERSION" -lt "500" ]; then
    echo_c "You are currently on a pre-2026R1 version of Nagios Network Analyzer. \
Please use the migration script to upgrade to NNA 2026R1. \
From there you can continue to upgrade to the latest version." "$RED"
    echo_c "For more information see the documentation at \
https://assets.nagios.com/downloads/nagios-network-analyzer/docs/Migrating-from-Network-Analyzer-2024-to-2026.pdf" "$RED"
    exit 1
fi

# Verify server has needed prereqs
cp "$BASE_DIR/nagiosna/app/Console/Commands/CheckPrereqsCommand.php" "$PROD_DIR/app/Console/Commands/CheckPrereqsCommand.php"
cp "$BASE_DIR/nagiosna/app/Services/MaintenanceService.php" "$PROD_DIR/app/Services/MaintenanceService.php"
if ! (php "$PROD_DIR/artisan" prereqs:check); then
    exit 1
fi

# Ensure Suricata is not running
if command -v suricata >/dev/null 2>&1; then
    suricata_bin=$(which suricata)
    suricata_pid=$(pgrep -u nna -f "$suricata_bin" 2>/dev/null | head -n 1)

    if [ -n "$suricata_pid" ]; then
        echo_c "ERROR: Suricata is currently running. Please stop Suricata via the web interface before upgrading." "$RED"
        exit 1
    fi
fi

# Ensure packages are installed
echo_c "Installing packages..." "$BLUE"
# shared_pkgs=""
# shared_python_pkgs=""

# if [[ "$distro" == "Ubuntu" || "$distro" == "Debian" ]]; then
#     pkgs=""
#     python_pkgs=""

#     apt-get -y update
#     apt -y install $shared_pkgs $pkgs
#     apt -y install $shared_python_pkgs $python_pkgs
# else
#     pkgs=""
#     python_pkgs=""

#     dnf -y update
#     dnf -y install $shared_pkgs $pkgs
#     dnf -y install $shared_python_pkgs $python_pkgs
# fi

# Upgrade sourceguardian loader
echo_c "Upgrading SourceGuardian loader..." "$BLUE"
install_sourceguardian
if [ `command -v systemctl` ]; then
    systemctl restart $httpd
else
    service $httpd restart
fi

# Backup the .env file
cp "$PROD_DIR/.env" /store/backups/nagiosna/.nagiosna.env.backup
if [ ! -f /store/backups/nagiosna/.nagiosna.env.backup ]; then
    echo_c "Failed to backup .env file!" "$RED"
    exit 1
fi

# Copy new application files
echo_c "Copying new application files..." "$BLUE"
cp -rf "$BASE_DIR"/mibs/* "$mibsdir"
cp -rf "$BASE_DIR"/scripts/* "$SCRIPTS_DIR"
cp -rf "$BASE_DIR"/nagiosna/* "$PROD_DIR"

# Restore the .env file
cp /store/backups/nagiosna/.nagiosna.env.backup "$PROD_DIR/.env"

# Run DB migrations
echo_c "Running database migrations..." "$BLUE"
php "$ARTISAN" migrate --force

# Permissions for Laravel directories
echo_c "Setting up permissions..." "$BLUE"
chown -R "$apacheuser":nnacmd "$PROD_DIR/storage" "$PROD_DIR/bootstrap/cache"
chmod -R 0775 "$PROD_DIR/storage"
chmod -R 0775 "$PROD_DIR/bootstrap/cache"

# Permissions for logs
chown -R "$apacheuser":nnacmd "$PROD_DIR/storage/logs"
chmod -R 2775 "$PROD_DIR/storage/logs"
touch "$PROD_DIR/storage/logs/cron.log"
chown nna:nnacmd "$PROD_DIR/storage/logs/cron.log"
chmod 664 "$PROD_DIR/storage/logs/cron.log"

# Permissions for backend directories
chown -R nna:nnacmd "$BACKEND_DIR"
chmod -R 0775 "$BACKEND_DIR"
chown root:nnacmd "$BACKEND_DIR/scripts"
chmod 0755 "$BACKEND_DIR/scripts"

# Copy sudoers file over
if [ -d /etc/sudoers.d/ ]; then
    cp -f "$BASE_DIR/nagiosna.sudoers" /etc/sudoers.d/nagiosna
else
    # Remove old sudoers entries
    grep -v 'Defaults:%nnacmd' /etc/sudoers > /etc/sudoers.new
    mv -f /etc/sudoers.new /etc/sudoers

    # Add new sudoers entries
    cat "$BASE_DIR/nagiosna.sudoers" >> /etc/sudoers
    chmod 440 /etc/sudoers
fi

# Upgrade Suricata
if command -v suricata &>/dev/null; then
    suricata_version=`/usr/local/bin/suricata -V | awk '{print $5}'`
    suricata_latest_version="8.0.3"
    if [ "$suricata_version" = "$suricata_latest_version" ]; then
        echo_c "Suricata is already at the latest version, skipping Suricata upgrade..." "$ORANGE"
    else
        echo_c "Upgrading Suricata to latest version..." "$BLUE"
        $BASE_DIR/scripts/upgrade_suricata.sh --suricata-version "$suricata_latest_version"
    fi
else
    echo_c "Suricata is not currently installed, skipping Suricata upgrade..." "$ORANGE"
fi

#### VERSION SPECIFIC UPDATES ####

# NA 2026R1.0.1
if [ "$OLD_VERSION" -lt "501" ]; then
    sed -i "s|^\s*ServerName .*|    ServerName $(hostname -I | awk '{print $1}')|" "${httpdconfdir}/nna.conf"
    php "$ARTISAN" db:seed --force --class=_2026R1_0_1_Seeder
fi

# NA 2026R1.1
if [ "$OLD_VERSION" -lt "510" ]; then
    if [ "$INTERACTIVE" = "True" ]; then
        echo
        echo_c "Enter a password to use for the InfluxDB nagiosna user. It must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, and one digit. A random password will be chosen if one is not entered..." "$GREEN"
        prompt_for_password NAGIOSNA_INFLUX_PASS
        echo
    fi

    # Generate passwords if not set
    if [ -z "$NAGIOSNA_INFLUX_PASS" ]; then
        NAGIOSNA_INFLUX_PASS="$(generate_mysql_password)"
        echo_c "The InfluxDB nagiosna password will be: $NAGIOSNA_INFLUX_PASS" "$ORANGE"
    fi

    ROOT_INFLUX_PASS="$(generate_mysql_password)"
    echo_c "The InfluxDB root password will be: $ROOT_INFLUX_PASS" "$ORANGE"

    export NAGIOSNA_INFLUX_PASS
    export ROOT_INFLUX_PASS

    # Install and configure InfluxDB
    install_influxdb
    install_influxdb_python_client
    configure_influxdb "$PROD_DIR"

    echo_c "Beginning migrating data from RRD files to InfluxDB..." "$BLUE"

    # Query MySQL for sources
    echo "Fetching sources from database..."
    mapfile -t sources < <(mysql -h "$DB_HOST" -u "$DB_USERNAME" \
        --batch --raw -N \
        -e "SELECT id, directory FROM sources WHERE directory IS NOT NULL AND directory != '';" \
        "$DB_DATABASE" 2>/dev/null)

    # Query MySQL for traffic profiles (formerly views, renamed by migration)
    echo "Fetching traffic profiles from database..."
    mapfile -t views < <(mysql -h "$DB_HOST" -u "$DB_USERNAME" \
        --batch --raw -N \
        -e "SELECT id, name FROM traffic_profiles;" \
        "$DB_DATABASE" 2>/dev/null)

    # Check if we got any sources
    if [ ${#sources[@]} -eq 0 ]; then
        echo "No sources found in database."
    else
        echo "Found ${#sources[@]} sources to migrate."

        for source_row in "${sources[@]}"; do
            # Split the row into columns (tab-separated by default)
            IFS=$'\t' read -r source_id directory <<< "$source_row"

            echo "Migrating source ID: $source_id, Directory: $directory"

            rrd_file="$directory/bandwidth.rrd"
            if [ -f "$rrd_file" ]; then
                python3 "$SCRIPTS_DIR/migrate_rrd_to_influx.py" "$rrd_file" "$source_id"
                echo "Migrated source $source_id"
            else
                echo "Warning: RRD file not found: $rrd_file"
            fi

            views_dir="$directory/views"
            if [ -d "$views_dir" ]; then
                echo "Found views directory for source $source_id"

                for view_row in "${views[@]}"; do
                    IFS=$'\t' read -r view_id view_name <<< "$view_row"

                    # Convert view name to filename format (remove spaces, add -bandwidth.rrd)
                    view_filename="${view_name// /}-bandwidth.rrd"
                    view_rrd_file="$views_dir/$view_filename"

                    if [ -f "$view_rrd_file" ]; then
                        python3 "$SCRIPTS_DIR/migrate_rrd_to_influx.py" "$view_rrd_file" "$source_id" "$view_id"
                        echo "Migrated view $view_id ($view_name)"
                    fi
                done
            fi
        done
        echo_c "RRD to InfluxDB migration complete!" "$GREEN"
    fi

    php "$ARTISAN" db:seed --force --class=_2026R1_1_Seeder

    echo_c "Upgrading Chrome for Testing..." "$BLUE"
    "$BASE_DIR/subcomponents/chrome/install.sh"
fi

# NA 2026R1.2
if [ "$OLD_VERSION" -lt "520" ]; then
    sed -i '/^[[:space:]]*file=.*supervisor\.sock/a\    chmod=0770' "$SUPERVISOR_CONFIG"
    sed -i '/^[[:space:]]*file=.*supervisor\.sock/a\    chown=root:nnacmd' "$SUPERVISOR_CONFIG"

    # Create systemd service for readSuricata if suricata is installed
    if command -v suricata >/dev/null 2>&1; then
        echo_c "Creating systemd service for readSuricata..." "$BLUE"
        sudo tee /etc/systemd/system/readsuricata.service > /dev/null << 'EOF'
[Unit]
Description=Read Suricata eve.json and push to DB

[Service]
Type=simple
User=nna
Group=nnacmd
WorkingDirectory=/usr/local/nagiosna/scripts/suricata
ExecStart=/usr/local/nagiosna/scripts/suricata/readSuricata
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

        sudo systemctl daemon-reload
    fi

    mkdir -p $SUPERVISOR_SYSTEMD_SERVICE_DIR
    cat > $SUPERVISOR_SYSTEMD_SERVICE_OVERRIDE <<EOF
    [Unit]
    After=rc-local.service mysqld.service
    Requires=mysqld.service
EOF

    mkdir -p "$PROD_DIR/storage/logs/updates"
    chown "$apacheuser":nnacmd "$PROD_DIR/storage/logs/updates"
    chmod 2775 "$PROD_DIR/storage/logs/updates"
    cp "$BASE_DIR/nagiosna-update.service" "/etc/systemd/system/nagiosna-update.service"
    systemctl daemon-reload

    php "$ARTISAN" db:seed --force --class=_2026R1_2_Seeder

    echo_c "Populating traffic profile source linker..." "$BLUE"

    # Query MySQL for sources with directories
    mapfile -t sources < <(mysql -h "$DB_HOST" -u "$DB_USERNAME" \
        --batch --raw -N \
        -e "SELECT id, directory FROM sources WHERE directory IS NOT NULL AND directory != '';" \
        "$DB_DATABASE" 2>/dev/null)

    # Query MySQL for traffic profiles to match against filesystem names
    mapfile -t profiles < <(mysql -h "$DB_HOST" -u "$DB_USERNAME" \
        --batch --raw -N \
        -e "SELECT id, name FROM traffic_profiles;" \
        "$DB_DATABASE" 2>/dev/null)

    for source_row in "${sources[@]}"; do
        IFS=$'\t' read -r source_id directory <<< "$source_row"

        views_dir="$directory/views"
        if [ -d "$views_dir" ]; then
            for profile_row in "${profiles[@]}"; do
                IFS=$'\t' read -r profile_id profile_name <<< "$profile_row"

                # Match filesystem name using same logic as getDirectoryName() / reap_files.py
                profile_filename="${profile_name// /}-bandwidth.rrd"
                if [ -f "$views_dir/$profile_filename" ]; then
                    mysql -h "$DB_HOST" -u "$DB_USERNAME" "$DB_DATABASE" 2>/dev/null \
                        -e "INSERT IGNORE INTO traffic_profile_linker (traffic_profile_id, source_id) VALUES ($profile_id, $source_id);"
                    echo "Linked traffic profile $profile_id ($profile_name) to source $source_id"
                fi
            done
        fi
    done

    echo_c "Traffic profile linker population complete!" "$GREEN"

    echo_c "Renaming existing views directories to profiles..." "$BLUE"

    for source_row in "${sources[@]}"; do
        IFS=$'\t' read -r source_id directory <<< "$source_row"

        views_dir="$directory/views"
        profiles_dir="$directory/profiles"

        if [ -d "$views_dir" ] && [ ! -d "$profiles_dir" ]; then
            echo "Renaming: $views_dir -> $profiles_dir"
            mv "$views_dir" "$profiles_dir"
        elif [ -d "$views_dir" ] && [ -d "$profiles_dir" ]; then
            echo "Warning: Both views and profiles directories exist for source $source_id"
        fi
    done

    echo_c "Directory renaming complete!" "$GREEN"

    echo_c "Upgrading Chrome for Testing..." "$BLUE"
    "$BASE_DIR/subcomponents/chrome/install.sh"
fi

# NA Version 2026R1.3  Version number may need to be updated later
if [ "$OLD_VERSION" -lt "530" ]; then
    # Fix ca-certificates directory ownership for Debian/Ubuntu cert uploads
    if [[ "$distro" == "Ubuntu" || "$distro" == "Debian" ]]; then
        mkdir -p /usr/local/share/ca-certificates
        chown "$apacheuser":nnacmd /usr/local/share/ca-certificates
        chmod 775 /usr/local/share/ca-certificates
    fi

    # Set the app name in the .env file
    sed -i 's/^APP_NAME=.*/APP_NAME="Nagios Network Analyzer"/' "$PROD_DIR/.env"
fi


### RESTART SERVICES ###
echo_c "Restarting services..." "$BLUE"
php "$ARTISAN" schedule:interrupt

echo "Reloading Supervisor config..."
supervisorctl reread
supervisorctl update

echo "Restarting Supervisor processes..."
supervisorctl restart all || echo_c "Warning: Some worker processes may have exited abnormally, continuing..." "$ORANGE"


### PRINT COMPLETION BANNER ###

IP_ADDRESS="$(hostname -I | awk '{print $1}')"
URL="http://$IP_ADDRESS"
URL_LENGTH=${#URL}
INNER_WIDTH=52
TOTAL_PADDING=$((INNER_WIDTH - URL_LENGTH))
LEFT_PADDING=$((TOTAL_PADDING / 2))
RIGHT_PADDING=$((TOTAL_PADDING - LEFT_PADDING))

echo
echo_c "######################################################" "$CYAN"
echo_c "#                                                    #" "$CYAN"
echo_c "#      Nagios Network Analyzer Upgrade Complete!     #" "$CYAN"
echo_c "#                                                    #" "$CYAN"
echo_c "# -------------------------------------------------- #" "$CYAN"
echo_c "#                                                    #" "$CYAN"
echo_c "#       Access the web interface by visiting:        #" "$CYAN"
printf "${CYAN}#${NC}%*s${BLUE}%s${NC}%*s${CYAN}#${NC}\n" \
    "$LEFT_PADDING" "" "$URL" "$RIGHT_PADDING" ""
echo_c "#                                                    #" "$CYAN"
echo_c "######################################################" "$CYAN"
echo
