#!/bin/bash

. ./libinstall.sh

export distro
export dist

# Force the install even if the nagiosna directory exists
FORCE=0

# INSTALL_PATH is current dir for use in making install dir independent
INSTALL_PATH=`pwd`

proddir="/var/www/html/nagiosna"
backenddir="/usr/local/nagiosna"

do_install_check

install_help() {
    cat <<-EOF
        Nagios Network Analyzer Installer
        Copyright 2025-, Nagios Enterprises LLC.
        License:
            Nagios Software License <http://assets.nagios.com/licenses/nagios_software_license.txt>

        Usage: ./fullinstall [options...]

        Options:
            -h | --help
                Display this help text
            -f | --force
                Force install (remove existing installation)
EOF
}

nagiosna() {
    echo_c "Copying application files..." "$BLUE"
    mkdir -p "$proddir"
    cd $INSTALL_PATH
    cp -r nagiosna /var/www/html/
    cp "$proddir/.env.example" "$proddir/.env"
}

prereqs() {
    if ! path_is_ok; then
        echo_c "Your system \$PATH does not include /sbin and /usr/sbin." "$BLUE"
        echo_c "Adding /sbin and /usr/sbin to \$PATH." "$BLUE"
        PATH="$PATH:/usr/sbin:/sbin"
    fi

    echo_c "Installing packages..." "$BLUE"

    # Shared packages for both distros
    shared_pkgs="php php-cli php-common php-fpm php-opcache flex bison php-gd php-mbstring php-xml gcc make libtool php-ldap whois curl unzip"
    shared_python_pkgs="python3 python3-pip python3-numpy python3-dateutil"

    if [[ "$distro" == "Ubuntu" || "$distro" == "Debian" ]]; then
        pkgs="apache2 php-mysql libcairo2-dev libglib2.0-dev libxml2-dev libpango1.0-dev libbz2-dev libsnmp-dev php-curl php-zip php-dev cron ldap-utils libldap-common"
        python_pkgs="python3-dev default-libmysqlclient-dev python3-mysqldb"

        if [ "$dist" = "debian12" ] || [ "$dist" = "debian13" ]; then
            pkgs="$pkgs mariadb-server"
        else
            pkgs="$pkgs mysql-server"
        fi

        apt-get update
        apt install $shared_pkgs $pkgs -y 
        apt install $shared_python_pkgs $python_pkgs -y
        apt install supervisor -y
    else
        pkgs="httpd php-mysqlnd cairo-devel glib2-devel libxml2-devel pango-devel bzip2-devel net-snmp-devel php-devel cronie"
        python_pkgs="python3-devel python3-mysqlclient"

        if [ "$dist" == "el9" ] || [ "$dist" == "el10" ]; then
            # Enable codeready builder repo
            if [ "$distro" == "RedHatEnterpriseServer" ] && [ "$dist" == "el9" ]; then
                yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
                subscription-manager repos --enable codeready-builder-for-rhel-9-x86_64-rpms
            elif [ "$distro" == "OracleServer" ] && [ "$dist" == "el9" ]; then
                yum install epel-release -y
                yum config-manager --set-enabled ol9_codeready_builder
            elif [ "$distro" == "OracleServer" ] && [ "$dist" == "el10" ]; then
                yum install oracle-epel-release-el10 -y
                yum config-manager --set-enabled ol10_codeready_builder
            elif [[ "$dist" == "el9" || "$dist" == "el10" ]] && rpm -q centos-stream-release; then
                dnf install epel-release -y
                dnf config-manager --set-enabled crb
            fi
        fi

        if [ "$dist" == "el10" ]; then
            IS_MARIA_DB="True"
            pkgs="$pkgs mariadb-server"
        else 
            dnf module enable php:8.2 -y

            IS_MARIA_DB="False"
            pkgs="$pkgs mysql-server"
        fi
        
        # required for python3-mysqlclient
        dnf install $shared_pkgs $pkgs -y
        dnf install $shared_python_pkgs $python_pkgs -y
        dnf install supervisor -y

        systemctl enable --now crond
    fi
}

firewall() {
    if [ "$distro" != "Ubuntu" ] && [ "$distro" != "Debian" ]; then
        # Opens default Apache ports and default master port
        open_tcp_ports 80 443 8080
    fi
}

library_path() {
    if [ "$architecture" == "x86_64" ];
    then
        echo '/usr/local/lib' >> /etc/ld.so.conf.d/nagiosna.conf
        echo '/usr/local/lib64' >> /etc/ld.so.conf.d/nagiosna.conf
    else
        echo '/usr/local/lib' >> /etc/ld.so.conf.d/nagiosna.conf
    fi
    ldconfig
}

db() {
    echo_c "Setting up the MySQL database..." "$BLUE"
    if [[ "$distro" == "Ubuntu" || "$distro" == "Debian" ]]; then
        systemctl start mysql
        systemctl enable mysql
    else
        if [ "$IS_MARIA_DB" == "True" ]; then
            systemctl start mariadb
            systemctl enable mariadb
        else
            systemctl start mysqld
            systemctl enable mysqld
        fi
    fi

    DB_EXISTS=$(mysql -u root -sse "SHOW DATABASES LIKE 'nagiosna'")
    if [ "$DB_EXISTS" != "nagiosna" ]; then
        mysql -u root -e "CREATE DATABASE nagiosna CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
    else
    echo_c "Database 'nagiosna' already exists." "$RED"
    fi 

    USER_EXISTS=$(mysql -u root -sse "SELECT EXISTS(SELECT 1 FROM mysql.user WHERE user = 'nagiosna' AND host = 'localhost')")
    if [ "$USER_EXISTS" -eq 0 ]; then
    mysql -u root -e "CREATE USER 'nagiosna'@'localhost' IDENTIFIED BY 'nagiosna';"
    else
    echo_c "User 'nagiosna'@'localhost' already exists." "$RED"
    fi

    mysql -u root -e "GRANT ALL PRIVILEGES ON nagiosna.* TO 'nagiosna'@'localhost';"
    mysql -u root -e "FLUSH PRIVILEGES;"

    # Generate env key
    cd "$proddir" && php artisan key:generate

    # Run migrations immediately
    echo_c "Running database migrations..." "$BLUE"
    cd "$proddir" && php artisan migrate --force
}

build_subcomponents() {
    cd "$INSTALL_PATH/subcomponents"

    # Install NFDump
    if command -v nfdump >/dev/null 2>&1; then
        echo_c "nfdump is already installed, skipping nfdump installation." "$RED"
    else
        echo_c "Installing nfdump..." "$BLUE"
        tar xf nfdump-1.7.6.tar.gz
        cd nfdump-1.7.6
        ./autogen.sh
        ./configure --enable-sflow --enable-nsel
        make
        make install
        ldconfig
        cd ..
        rm -rf nfdump-1.7.6
    fi

    # Install rrdtool
    if command -v rrdtool >/dev/null 2>&1; then
        echo_c "RRDtool is already installed, skipping RRDtool installation." "$RED"
    else
        echo_c "Installing rrdtool..." "$BLUE"
        tar xf rrdtool-1.7.2.tar.gz
        cd rrdtool-1.7.2
        mkdir -p /root/.python-eggs
        ./configure --prefix=/usr/local --disable-perl
        make
        make install
        ldconfig
        # Install python (and ignore temp file location perm warn)
        make site-python-install &>/dev/null
        cd ..
        rm -rf rrdtool-1.7.2

        # Add /usr/local/lib to the list of directories the system searches for shared libraries
        # echo "/usr/local/lib" | sudo tee /etc/ld.so.conf.d/local.conf
        # sudo ldconfig
    fi

    # Make sure librrd exists for el9
    if [ "$dist" == "el9" ]; then
        # found some systems where librrd is already installed, install script crashes here if we try to clobber.
        if [ ! -f /usr/lib64/librrd.so.8 ]; then
            ln -s /usr/local/lib/librrd.so.8 /usr/lib64/librrd.so.8
        fi
    fi

    # Install Chrome for Testing
    cd chrome
    ./install.sh
    cd ..
}

backend() {
    # Setup the backend daemon for netflow processing
    echo_c "Setting up permissions..." "$BLUE"
    add_user nna
    add_group nnacmd
    add_to_groups nna nnacmd
    add_to_groups "$apacheuser" nnacmd
    add_to_groups nna "$apacheuser"

    # Permissions for Laravel directories
    chown -R "$apacheuser":nnacmd "$proddir/storage" "$proddir/bootstrap/cache"
    chmod -R 0775 "$proddir/storage"
    chmod -R 0775 "$proddir/bootstrap/cache"
    cd "$proddir" && php artisan storage:link

    # Manually create laravel.log and cron.log
    touch "$proddir/storage/logs/laravel.log"
    chown "$apacheuser":nnacmd "$proddir/storage/logs/laravel.log"
    chmod 664 "$proddir/storage/logs/laravel.log"
    touch "$proddir/storage/logs/cron.log"
    chown nna:nnacmd "$proddir/storage/logs/cron.log"
    chmod 664 "$proddir/storage/logs/cron.log"
    
    mkdir -p "$backenddir/scripts"
    mkdir -p "$backenddir/var"
    cp -r "$INSTALL_PATH/scripts/"* "$backenddir/scripts/"

    chown -R nna:nnacmd "$backenddir"
    chmod -R 0775 "$backenddir"
    chown -R nna:nnacmd "$backenddir/var"
    # For security - this prevents nna from overwriting a file that it can run via `sudo`
    chown root:nnacmd "$backenddir/scripts"
    chmod 0755 "$backenddir/scripts"

    # Change permissions to prevent malicious file modifications from apache/nna users
    chmod 0755 "$backenddir/scripts/source_controller.py"
    # chmod 0555 "$backenddir/bin/nagiosna"
    # chmod 0755 "$backenddir/scripts/change_timezone.sh"
    # chmod 0755 "$backenddir/scripts/upgrade_to_latest.sh"
    chmod 0755 "$backenddir/scripts/manage_firewall.sh"
    chmod 0755 "$backenddir/scripts/remove_source.sh"
    chown root:nnacmd "$backenddir/scripts/source_controller.py"
    # chown root.root "$backenddir/bin/nagiosna"
    # chown root:nnacmd "$backenddir/scripts/change_timezone.sh"
    # chown root:nnacmd "$backenddir/scripts/upgrade_to_latest.sh"
    chown root:nnacmd "$backenddir/scripts/manage_firewall.sh"
    chown root:nnacmd "$backenddir/scripts/remove_source.sh"

    # Create backup directories for backup/restore scripts
    mkdir -p /store/backups/nagiosna
    chown -R nna:nnacmd /store
    chmod -R 0775 /store
}

install_sudo() {
    # set sudoers for backend functions
    if [ -d /etc/sudoers.d/ ]; then
        cp "$INSTALL_PATH/nagiosna.sudoers" /etc/sudoers.d/nagiosna
    else
        cat "$INSTALL_PATH/nagiosna.sudoers" >> /etc/sudoers
    fi
}

selinux() {
    # Disable SELinux if it's enabled. This should be done on RHEL-based systems.
    if [ "$distro" != "Ubuntu" ] && [ "$distro" != "Debian" ]; then
        disable_selinux

        semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/html/nagiosna/storage(/.*)?"
        semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/html/nagiosna/bootstrap/cache(/.*)?"
        restorecon -Rv /var/www/html/nagiosna/storage
        restorecon -Rv /var/www/html/nagiosna/bootstrap/cache
        setsebool -P httpd_can_network_connect_db 1
    fi
}

apache() {
    echo_c "Creating Apache config file..." "$BLUE"
    if [[ "$distro" == "Ubuntu" || "$distro" == "Debian" ]]; then
        # Activate module mod_rewrite and ssl
        a2enmod ssl
        a2enmod rewrite
        a2ensite default-ssl

        # Remove the default configuration
        a2dissite 000-default.conf

        # Copy over our version (add Document Root)
        echo "DocumentRoot /var/www/html" > "$httpdconfdir/nna.conf"
        cat "$INSTALL_PATH/nna.conf" >> "$httpdconfdir/nna.conf"

        echo "ErrorLog /var/log/$httpd/laravel-error.log" >> "$httpdconfdir/nna.conf"
        echo "CustomLog /var/log/$httpd/laravel-access.log combined" >> "$httpdconfdir/nna.conf"
        echo "</VirtualHost>" >> "$httpdconfdir/nna.conf"

        a2ensite nna.conf
        systemctl restart apache2
    else
        cp "$INSTALL_PATH/nna.conf" $httpdconfdir

        echo "ErrorLog /var/log/$httpd/laravel-error.log" >> "$httpdconfdir/nna.conf"
        echo "CustomLog /var/log/$httpd/laravel-access.log combined" >> "$httpdconfdir/nna.conf"
        echo "</VirtualHost>" >> "$httpdconfdir/nna.conf"
    fi

    IP=$(hostname -I | awk '{print $1}')
    sed -i "s|^APP_URL=.*|APP_URL=http://$IP|" "$proddir/.env"
    sed -i "s|^ServerName=.*|ServerName $IP|" "${httpdconfdir}/nna.conf"

    echo_c "Setting up Apache..." "$BLUE"
    php_fpm_service=""
    if [[ "$distro" == "Ubuntu" || "$distro" == "Debian" ]]; then
        # Find the installed PHP-FPM service by checking common versions
        for version in 8.4 8.3 8.2; do
            if systemctl list-units --full -all | grep -q "php${version}-fpm.service"; then
                php_fpm_service="php${version}-fpm"
                break
            fi
        done
    else
        php_fpm_service="php-fpm"
    fi

    systemctl enable --now "$php_fpm_service"
    systemctl enable $httpd
    systemctl restart "$httpd"
}

daemons() {
    PHP_PATH="$(which php)"
    
    # Install Laravel Reverb
    echo_c "Installing Reverb..." "$BLUE"
    cd "$proddir" && php artisan reverb:install --no-interaction

    # TODO: is this even needed anymore?
    # make a new env key for .env file
    cd "$proddir" && php artisan key:generate

    # Create cron job for Laravel scheduler
    echo_c "Setting up Laravel scheduler cron job..." "$BLUE"
    CRON_JOB="* * * * * nna cd $proddir && $PHP_PATH artisan schedule:run >> $proddir/storage/logs/cron.log 2>&1"
    echo "$CRON_JOB" > /etc/cron.d/nagiosna
    chmod 644 /etc/cron.d/nagiosna
    echo "Crontab for nna set to: $CRON_JOB"

    # Create an executable PHP binary for nna user
    EXE_PHP_PATH="/usr/local/bin/herd-php"
    rm -f "$EXE_PHP_PATH"
    cp $PHP_PATH $EXE_PHP_PATH
    chmod 755 $EXE_PHP_PATH
    chown root:nnacmd $EXE_PHP_PATH

    # Setup Supervisor for Laravel queues and Reverb
    echo_c "Setting up Supervisor..." "$BLUE"
    LOG_FILE_DIR="$proddir/storage/logs"

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

    cat > $SUPERVISOR_CONFIG <<EOF
    [unix_http_server]
    file=/var/run/supervisor.sock    ; (path to the socket file)

    [supervisord]
    logfile=/var/log/supervisord.log ; (main log file)
    logfile_maxbytes=50MB            ; (num of main logfile bytes b4 rotation;default 50MB)
    logfile_backups=10               ; (num of main logfile rotation backups;default 10)
    loglevel=info                    ; (log level;default info; others: debug,warn,trace)
    nodaemon=false                   ; (start in foreground if true;default false)
    minfds=1024                      ; (min. avail startup file descriptors;default 1024)
    minprocs=200                     ; (min. avail process descriptors;default 200)
    pidfile=/var/run/supervisord.pid ; pidfile

    [rpcinterface:supervisor]
    supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

    [supervisorctl]
    serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL  for a unix socket

    [include]
    files = $SUPERVISOR_INCLUDES_DIR/*.ini
EOF

    cat > "$SUPERVISOR_INCLUDES_DIR/laravel-worker.ini" <<EOF
    [program:laravel-worker]
    process_name=%(program_name)s_%(process_num)02d
    command=$EXE_PHP_PATH $proddir/artisan queue:work --max-jobs=500
    autostart=true
    autorestart=true
    stopasgroup=true
    killasgroup=true
    user=nna
    numprocs=8
    redirect_stderr=true
    stdout_logfile=$LOG_FILE_DIR/worker.log
    stopwaitsecs=3600
EOF

    cat > "$SUPERVISOR_INCLUDES_DIR/laravel-reverb.ini" <<EOF
    [program:laravel-reverb]
    command=$EXE_PHP_PATH $proddir/artisan reverb:start
    autostart=true
    autorestart=true
    stopasgroup=true
    killasgroup=true
    user=nna
    redirect_stderr=true
    stdout_logfile=$LOG_FILE_DIR/reverb.log
EOF

    if ! pgrep -x "supervisord" > /dev/null; then
        echo "Starting supervisord..."
        systemctl enable supervisord
        systemctl start supervisord
    else
        echo "supervisord is already running. Restarting processes..."
        supervisorctl stop all
    fi

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

    echo "Starting new processes..."
    supervisorctl start all
    sleep 2
    status_output=$(supervisorctl status)

    if echo "$status_output" | grep -q "^laravel-reverb.*RUNNING"; then
        echo "laravel-reverb is running."
    else
        echo_c "Error: laravel-reverb is not running" "$RED"
        exit 1
    fi

    worker_count=$(echo "$status_output" | grep -E "^laravel-worker:laravel-worker_[0-9]+" | wc -l)
    running_worker_count=$(echo "$status_output" | grep -E "^laravel-worker:laravel-worker_[0-9]+.*RUNNING" | wc -l)
    if [ "$worker_count" -eq "$running_worker_count" ]; then
        echo "All $running_worker_count laravel-worker processes are running."
    else
        echo_c "Error: Some laravel-worker processes are not running" "$RED"
        echo "$status_output" | grep "^laravel-worker"
        exit 1
    fi

    echo "Supervisor setup completed!"
}

configure_ldap() {  
    # ldap configs, will change as needed
    if [ "$distro" == "Ubuntu" ] || [ "$distro" == "Debian" ]; then
        ldap_config="/etc/ldap/ldap.conf"
        ldap_dir="/etc/ldap"
        cacerts_dir="/etc/ldap/cacerts"
    else
        ldap_config="/etc/openldap/ldap.conf"
        ldap_dir="/etc/openldap"
        cacerts_dir="/etc/openldap/cacerts"
    fi

    mkdir -p $cacerts_dir
    mkdir -p $ldap_dir/certs
    chmod 664 $ldap_config
    chmod 775 $ldap_dir $ldap_dir/certs $cacerts_dir
    chown -R $apacheuser:nnacmd $ldap_dir
}

##############################
### START THE INSTALLATION ###
##############################

fullinstall() {
    # Parse command line
    while [ -n "$1" ]; do
        case "$1" in
            -h | --help)
                install_help
                exit 0
                ;;
            -f | --force)
                export FORCE=1
                ;;
            *)
                echo "Unknown option:  $1" >&2
                usage_install >&2
                exit 1
        esac
        shift
    done

    print_header "Nagios Network Analyzer"

    # Verify that Nagios Network Analyzer is not already installed
    if [ -d "$proddir" ] || [ -d "$backenddir" ]; then
        if [ "${FORCE:-0}" -eq 0 ]; then
            echo_c "Error: It looks like Nagios Network Analyzer is already installed in:" "$RED"
            [ -d "$proddir" ] && echo_c "  - $proddir" "$RED"
            [ -d "$backenddir" ] && echo_c "  - $backenddir" "$RED"
            echo_c "If you know what you're doing you can run the installer with -f or --force to force the install." "$RED"
            exit 1
        else
            echo_c "Forcing install. Removing existing installation in $proddir..." "$BLUE"
            rm -rf "$proddir"
        fi
    fi

    nagiosna
    run_steps prereqs install_sourceguardian firewall library_path db build_subcomponents backend install_sudo selinux apache daemons configure_ldap

    trap - 0

    touch "$backenddir/.installed"

    echo
    echo "---------------------------------------------"
    echo_c "Nagios Network Analyzer Installation Complete!" "$BLUE"
    echo "---------------------------------------------"
    echo
    echo "You can finish the final setup steps for NagiosNA by visiting:"
    echo_c "    http://$IP/install" "$BLUE"
}

log_it install.log fullinstall "$@"