#!/bin/bash
# Script Name: mpsetup.sh
# Description: This script installs MultiPortal on various distribution
# Author: jbulalaque, Matthew Wood
# Date: 2026-03-05
# Version: 1.8
# Usage: ./mpsetup.sh [arguments]
# Notes: Add any special instructions or dependencies here.

set -euo pipefail
IFS=$'\n\t'

#set -e: Exit the script immediately if any command fails.
#set -u: Treat unset variables as an error.
#set -o pipefail: Catch errors in pipelines.
#IFS=$'\n\t': Avoid issues with word splitting.

#Variables

APP_NAME="MultiPortal"
FQDN=""
INSTALL_DIR="$(pwd)"
DB_HOST="localhost"
DB_NAME="multiportal"
DB_USER="multiportal"
DB_PASS="multiportal"
ROOT_PASS="$(openssl rand -base64 12)"
PHP_VERSION_REQUIRED="8.2"
CONSOLEPORT=8081
COOKIE_VALIDATION_KEY="$(openssl rand -base64 12)"

INSTALL_DIR="$(pwd)"
LOG_FILE="$INSTALL_DIR/mpinstall.log"

SSH_KEY_PATH=""

# Set the CaddyServer version and architecture
CADDY_VERSION="2.10.2"
CADDY_ARCH="amd64"

# Multiportal Repo URL
REPO_URL="https://downloads.multiportal.io/installer/mpInstallation"

SSLCER=""
SSLKEY=""

DSTCER="/var/lib/caddy/sslcer.cer"
DSTKEY="/var/lib/caddy/sslkey.key"

ENV_NAME=".env"
CADDYSERVER_CONF="/etc/caddy/Caddyfile"

DISTRO=""
PKGMGR=""
SUDO=""
HTTP_ONLY=""
MP_VERSION=""

# Setup sudo handling - handles fresh Debian where sudo may not be installed
# Sets SUDO variable: empty when root (no sudo needed), "sudo" when not root
setup_sudo() {
    if [ "$EUID" -eq 0 ]; then
        # Running as root - no sudo prefix needed for commands
        SUDO=""

        # On Debian/Ubuntu, install sudo package if not present
        # This is needed because some commands in the script explicitly need sudo
        # for proper user context switching even when running as root
        if [ -f /etc/debian_version ]; then
            if ! command -v sudo &>/dev/null; then
                echo "Installing sudo package on Debian..."
                apt-get update -qq --allow-releaseinfo-change
                apt-get install -y -qq sudo
            fi
        fi
    else
        # Not running as root - need sudo prefix
        if ! command -v sudo &>/dev/null; then
            echo "Error: sudo is not installed and you are not running as root."
            echo "Please either run this script as root, or install sudo first."
            exit 1
        fi
        SUDO="sudo"
    fi
}

accept_eula() {
    echo "---------------------------------------------"
    echo "          Welcome to MultiPortal!"
    echo "---------------------------------------------"
    echo ""
    echo "This script will:"
    echo "  - Install required dependencies, including PHP 8.2, MariaDB, Node.js, and related packages."
    echo "  - Download and set up the MultiPortal installer."
    echo "  - Configure and secure MariaDB for MultiPortal."
    echo "  - Install and configure CaddyServer as the web server for MultiPortal."
    echo "  - Configure and enable the MultiPortal service for systemd."
    echo "  - Set up Ioncube loader for PHP."
    echo "  - Configure and set up Node.js for WebSocket handling with PM2."
    echo "  - Finalize the MultiPortal installation."
    echo ""
    echo "---------------------------------------------"
    echo "        Please read and accept the EULA"
    echo "---------------------------------------------"
    echo "By proceeding, you agree to the EULA agreement."
    echo "The EULA can be reviewed at: https://multiportal.io/end-user-license-agreement"
    echo ""
    echo "Do you agree to the EULA agreement? (yes/no): "

    read -r response

  case "$response" in
    [Yy][Ee][Ss])
      print_info "Thank you for agreeing to the EULA. Proceeding..."
      return 0
      ;;
    [Nn][Oo])
      print_error "You did not agree to the EULA. Exiting..."
      print_info "Press any key to continue..."
      read -n1 -s
      exit 1
      ;;
    *)
      print_error "Invalid input. Please type 'yes' or 'no'."
      print_info "Press any key to continue..."
      read -n1 -s
      accept_eula
      ;;
  esac
}

print_usage() {
    echo "Usage: sudo $0 -f <your_fqdn> [-H]"
    echo "       sudo $0 -f <your_fqdn> -s <cert_path> -k <key_path>"
    echo "       sudo $0 -p <node2_ip,node3_ip>"
    echo ""
    echo "Options:"
    echo "  -f, --fqdn        Fully qualified domain name"
    echo "  -H, --http-only   Serve HTTP only (no HTTPS/TLS)"
    echo "  -s, --sslcert     Path to SSL certificate"
    echo "  -k, --sslkey      Path to SSL key"
    echo "  -p, --prepnodes   Prepare Galera cluster nodes"
    echo "  -c, --confignodes Configure Galera cluster nodes"
    echo "  -h, --help        Show this help message"
}

# Print a message in green for success or info
print_info() {
    echo -e "\e[32m$(date '+%Y-%m-%d %H:%M:%S') [INFO] $1\e[0m"
    echo "$(date '+%Y-%m-%d %H:%M:%S') [INFO] $1" >> "$LOG_FILE"
}

# Print a message in red for errors
print_error() {
    echo -e "\e[31m$(date '+%Y-%m-%d %H:%M:%S') [ERROR] $1\e[0m" >&2
    echo "$(date '+%Y-%m-%d %H:%M:%S') [ERROR] $1" >> "$LOG_FILE"
}

# Create or clear the log file
initialize_log() {
    echo "=== $APP_NAME Installer Log ===" > "$LOG_FILE"
    echo "Log started at $(date '+%Y-%m-%d %H:%M:%S')" >> "$LOG_FILE"
}

validate_input() {
    # Split and count the values for parameter -p using read with explicit delimiter
    IFS=',' read -ra VALUES <<< "$NODES"

    # Check if there are exactly two values
    if [ ${#VALUES[@]} -ne 2 ]; then
        echo "Error: You must provide exactly two values for -n (--prepnodes)."
        exit 1
    fi

    # Validate that both values are valid IP addresses
    for value in "${VALUES[@]}"; do
        if ! is_valid_ip "$value"; then
            echo "Error: '$value' is not a valid IP address."
            exit 1
        fi
    done
}

is_root_user() {
    if [ "$EUID" -eq 0 ]; then
        echo "You are running as root."
        return 0
    else
        echo "You are not running as root."
        return 1
    fi
} 

show_loader() {
    local pid=$1
    local delay=0.2
    local spin='-\|/'

    while ps -p "$pid" > /dev/null; do
        local temp=${spin#?}
        printf " [%c] " "$spin"
        local spin=$temp${spin%"$temp"}
        sleep $delay
        printf "\b\b\b\b\b"
    done

    printf "    \b\b\b\b"
}

show_loading_with_timer() {
    local pid=$1 # Process ID of the running command
    local delay=0.1
    local spinner='|/-\'
    local start_time=$(date +%s) # Record the start time

    while kill -0 "$pid" 2>/dev/null; do
        local current_time=$(date +%s)
        local elapsed=$((current_time - start_time))
        local minutes=$((elapsed / 60))
        local seconds=$((elapsed % 60))
        
        for i in $(seq 0 $((${#spinner} - 1))); do
            printf "\r[%c] Task Elapsed Time... %02d:%02d" "${spinner:$i:1}" "$minutes" "$seconds"
            sleep $delay
        done
    done
    printf "\n"
}

read_password() {
    password=""
    while IFS= read -r -s -n 1 char; do
        # Check for Enter (ASCII code 13)
        if [[ $char == $'\0' || $char == $'\n' ]]; then
            echo    # Print a newline when done
            break
        fi

        # Handle backspace
        if [[ $char == $'\177' ]]; then
            if [[ -n $password ]]; then
                # Remove last character from password
                password=${password%?}
                # Move cursor back, overwrite with space, and move back again
                echo -ne "\b \b"
            fi
        else
            # Append character to password
            password+="$char"
            # Display asterisk
            echo -n "*"
        fi
    done
    DB_PASS=$password
}

# Function to determine the distribution type
get_linux_distribution() {
    if [[ -f /etc/os-release ]]; then
        # Parse the ID field from /etc/os-release
        . /etc/os-release
        echo "$ID"
    elif [[ -f /etc/redhat-release ]]; then
        # For Red Hat-based distributions
        awk '{print $1}' /etc/redhat-release
    elif [[ -f /etc/debian_version ]]; then
        # For Debian-based distributions
        echo "Debian"
    else
        echo "Unknown"
    fi
}

# Function to determine the package manager
get_package_manager() {
    # List of common package managers to check
    local managers=("apt" "yum" "dnf" "pacman" "zypper" "brew" "port" "emerge" "apk" "pkg")

    for manager in "${managers[@]}"; do
        if command -v "$manager" &>/dev/null; then
            echo "$manager"
            return 0
        fi
    done

    # If no package manager is found
    echo "unknown"
    return 1
}

# Helper function for fully non-interactive apt installations
apt_install_noninteractive() {
    $SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y \
        -o Dpkg::Options::="--force-confdef" \
        -o Dpkg::Options::="--force-confold" \
        "$@"
}

# Configure apt for non-interactive operation (handles needrestart on Ubuntu 22.04+)
configure_noninteractive_apt() {
    export DEBIAN_FRONTEND=noninteractive
    export NEEDRESTART_MODE=a
    export NEEDRESTART_SUSPEND=1

    # Disable needrestart interactive mode if installed (Ubuntu 22.04+)
    if [ -f /etc/needrestart/needrestart.conf ]; then
        $SUDO sed -i "s/#\\\$nrconf{restart} = 'i';/\\\$nrconf{restart} = 'a';/" /etc/needrestart/needrestart.conf 2>/dev/null || true
    fi

    # Pre-configure GRUB to avoid prompts during kernel updates
    if command -v debconf-set-selections &>/dev/null; then
        echo 'grub-pc grub-pc/install_devices_empty boolean true' | $SUDO debconf-set-selections 2>/dev/null || true
    fi
}

disable_apache2() {
    # Check if the apache2 service is active
    if systemctl is-active --quiet apache2; then
        echo "Apache2 service is running. Stopping it now..."
        # Stop the apache2 service
        $SUDO systemctl stop apache2
        $SUDO systemctl disable apache2

        if [ $? -eq 0 ]; then
            echo "Apache2 service has been stopped and disabled successfully."
        else
            echo "Failed to stop and disabled the Apache2 service."
        fi
    else
        echo "Apache2 service is not installed, continuing..."
    fi
}


install_dependencies() {

    echo "Detected Linux Distribution: $DISTRO"
    echo "Detected package manager: $PKGMGR"
    echo "Installing required packages..."

    if [[ "$PKGMGR" == "apt" ]]; then

        # Configure apt for fully non-interactive operation
        configure_noninteractive_apt

        DEB_PHP_SETTINGS="/etc/php/8.2/fpm/php.ini"

        packages=(
            "debian-keyring"
            "debian-archive-keyring"
            "curl"
            "gnupg"
            "git"
            "unzip"
            "libicu-dev"
            "lsb-release"
            "ca-certificates"
            "wget"
        )

        # software-properties-common is only needed on Ubuntu (for add-apt-repository)
        # It has been removed from Debian 13 (Trixie)
        if [[ "$DISTRO" == "ubuntu" ]]; then
            packages+=("software-properties-common")
        fi

        echo "Updating package index..."
        $SUDO apt-get update -y --allow-releaseinfo-change

        echo "Installing initial packages..."
        # Loop through each package
        for package in "${packages[@]}"; do
            echo "Checking if $package is installed..."
            if ! dpkg -l | grep -q "^ii\s\+$package\s"; then
                echo "$package is not installed. Installing..."
                apt_install_noninteractive "$package"
                if [ $? -eq 0 ]; then
                    echo "$package installed successfully."
                else
                    echo "Failed to install $package. Please check your configuration or network connection."
                fi
            else
                echo "$package is already installed."
            fi
        done

        # sudo mkdir -p /etc/apt/keyrings
        # sudo curl -o /etc/apt/keyrings/mariadb-keyring.pgp 'https://mariadb.org/mariadb_release_signing_key.pgp'

        $SUDO curl -LsSO https://r.mariadb.com/downloads/mariadb_repo_setup
        $SUDO chmod +x ./mariadb_repo_setup
        # Debian 13 (trixie) may not be recognized by mariadb_repo_setup yet,
        # fall back to bookworm (binary-compatible) if trixie fails
        MARIADB_OS_VERSION="$(lsb_release -sc)"
        if ! $SUDO ./mariadb_repo_setup --mariadb-server-version="mariadb-11.6.2" \
            --os-type "$DISTRO" --os-version "$MARIADB_OS_VERSION" --skip-maxscale; then
            echo "MariaDB repo setup failed for '$MARIADB_OS_VERSION', retrying with 'bookworm'..."
            $SUDO ./mariadb_repo_setup --mariadb-server-version="mariadb-11.6.2" \
                --os-type debian --os-version bookworm --skip-maxscale
        fi

        mdb=(
            "mariadb-server"
            "mariadb-client"
            "galera-4"
            "mariadb-backup"
        )
        echo "Updating package index..."
        $SUDO apt-get update -y --allow-releaseinfo-change

        # Pre-seed MariaDB to skip interactive password prompts
        if command -v debconf-set-selections &>/dev/null; then
            echo "mariadb-server mysql-server/root_password password ''" | $SUDO debconf-set-selections
            echo "mariadb-server mysql-server/root_password_again password ''" | $SUDO debconf-set-selections
        fi

        echo "Installing MariaDB packages..."
        # Loop through each package
        for package in "${mdb[@]}"; do
            echo "Checking if $package is installed..."
            if ! dpkg -l | grep -q "^ii\s\+$package\s"; then
                echo "$package is not installed. Installing..."
                apt_install_noninteractive "$package"
                if [ $? -eq 0 ]; then
                    echo "$package installed successfully."
                else
                    echo "Failed to install $package. Please check your configuration or network connection."
                fi
            else
                echo "$package is already installed."
            fi
        done

        echo "Adding Sury repository for PHP 8.2"

        # Add Sury repository for PHP 8.2
        if [[ "$DISTRO" == "debian" ]]; then
            # Use modern keyring approach (compatible with Debian 12 and 13)
            $SUDO mkdir -p /usr/share/keyrings
            $SUDO curl -sSLo /usr/share/keyrings/deb.sury.org-php.gpg https://packages.sury.org/php/apt.gpg
            echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" \
                | $SUDO tee /etc/apt/sources.list.d/php.list

            # Pin Sury packages higher to prevent php-common conflicts on Debian 13+
            $SUDO tee /etc/apt/preferences.d/php-sury.pref > /dev/null <<PINEOF
Package: php* libapache2-mod-php*
Pin: origin packages.sury.org
Pin-Priority: 900
PINEOF
        elif [[ "$DISTRO" == "ubuntu" ]]; then
            # Ensure fully non-interactive for add-apt-repository
            $SUDO env DEBIAN_FRONTEND=noninteractive add-apt-repository ppa:ondrej/php -y
        else
            echo "Unable to identify distro"
            exit 1
        fi
        #Update APT Cache and Install PHP 8.2
        echo "Updating package index..."
        $SUDO apt-get update -y --allow-releaseinfo-change

        phppkgs=(
            "php8.2"
            "php8.2-fpm"
            "php8.2-common"
            "php8.2-curl"
            "php8.2-gd"
            "php8.2-mbstring"
            "php8.2-mysql"
            "php8.2-opcache"
            "php8.2-xml"
            "php8.2-zip"
	    "php8.2-ldap"
        )
        
        # Reset php-fpm failure state before installing to prevent rate-limit issues
        # The packages trigger service restarts during installation
        $SUDO systemctl reset-failed php8.2-fpm 2>/dev/null || true
        $SUDO systemctl stop php8.2-fpm 2>/dev/null || true

        # Build list of packages that need to be installed
        pkgs_to_install=()
        for phppkg in "${phppkgs[@]}"; do
            echo "Checking if $phppkg is installed..."
            if ! dpkg -l | grep -q "^ii\s\+$phppkg\s"; then
                echo "$phppkg needs to be installed."
                pkgs_to_install+=("$phppkg")
            else
                echo "$phppkg is already installed."
            fi
        done

        # Install all PHP packages in a single command to minimize service restart triggers
        if [ ${#pkgs_to_install[@]} -gt 0 ]; then
            echo "Installing PHP packages: ${pkgs_to_install[*]}"
            # Reset again right before install in case of prior failures
            $SUDO systemctl reset-failed php8.2-fpm 2>/dev/null || true
            apt_install_noninteractive "${pkgs_to_install[@]}"
            if [ $? -eq 0 ]; then
                echo "PHP packages installed successfully."
            else
                echo "Failed to install PHP packages. Please check your configuration or network connection."
                exit 1
            fi
        fi

        # Reset failure state after package installation (dpkg triggers may have caused failures)
        $SUDO systemctl reset-failed php8.2-fpm 2>/dev/null || true

        echo "Configuring PHP Settings"

        # #Configure PHP Settings
        $SUDO sed -i 's/^upload_max_filesize = .*/upload_max_filesize = 10G/' $DEB_PHP_SETTINGS
        $SUDO sed -i 's/^post_max_size = .*/post_max_size = 10G/' $DEB_PHP_SETTINGS
        $SUDO sed -i 's/^max_execution_time = .*/max_execution_time = 360/' $DEB_PHP_SETTINGS

        #Verify PHP Settings
        echo "Verify PHP Settings"
        $SUDO grep -E 'upload_max_filesize|post_max_size|max_execution_time' $DEB_PHP_SETTINGS

        #Restart PHP-FPM (reset-failed handles systemd rate-limit issues)
        $SUDO systemctl reset-failed php8.2-fpm 2>/dev/null || true
        sleep 2  # Brief delay to avoid rate-limiting
        $SUDO systemctl restart php8.2-fpm
        if ! systemctl is-active --quiet php8.2-fpm; then
            echo "Warning: php8.2-fpm failed to start after PHP configuration"
            $SUDO systemctl reset-failed php8.2-fpm 2>/dev/null || true
            sleep 5
            $SUDO systemctl start php8.2-fpm
            if ! systemctl is-active --quiet php8.2-fpm; then
                echo "ERROR: php8.2-fpm failed to start. Check 'systemctl status php8.2-fpm' for details."
                exit 1
            fi
        fi
        
        #Install IonCube
        echo "Installing Ioncube"
        # Download and extract IonCube in /tmp (using subshell to preserve current directory)
        (
            cd /tmp || exit 1
            $SUDO wget https://downloads.ioncube.com/loader_downloads/ioncube_loaders_lin_x86-64.tar.gz
            $SUDO tar -zxvf ioncube_loaders_lin_x86-64.tar.gz
        )

        #Copy IonCube Loader
        $SUDO cp /tmp/ioncube/ioncube_loader_lin_8.2.so "$(php -r "echo ini_get('extension_dir').PHP_EOL;")"

        install_caddyserver

        #Update Config Files - add IonCube if not already present
        IONCUBE_EXT="zend_extension=$(php -r "echo ini_get('extension_dir').PHP_EOL;")/ioncube_loader_lin_8.2.so"
        if ! grep -q "ioncube_loader" /etc/php/8.2/fpm/php.ini 2>/dev/null; then
            echo "$IONCUBE_EXT" | $SUDO tee -a /etc/php/8.2/fpm/php.ini
        else
            echo "IonCube already configured in fpm/php.ini"
        fi

        if ! grep -q "ioncube_loader" /etc/php/8.2/cli/php.ini 2>/dev/null; then
            echo "$IONCUBE_EXT" | $SUDO tee -a /etc/php/8.2/cli/php.ini
        else
            echo "IonCube already configured in cli/php.ini"
        fi

        #restart PHP-FPM (reset-failed handles systemd rate-limit issues)
        $SUDO systemctl reset-failed php8.2-fpm 2>/dev/null || true
        sleep 2  # Brief delay to avoid rate-limiting
        $SUDO systemctl restart php8.2-fpm
        $SUDO systemctl enable php8.2-fpm

        # Verify PHP-FPM started successfully
        if ! systemctl is-active --quiet php8.2-fpm; then
            echo "Warning: php8.2-fpm failed to start after IonCube configuration"
            $SUDO systemctl reset-failed php8.2-fpm 2>/dev/null || true
            sleep 5
            $SUDO systemctl start php8.2-fpm
            if ! systemctl is-active --quiet php8.2-fpm; then
                echo "ERROR: php8.2-fpm failed to start. Check 'systemctl status php8.2-fpm' for details."
                exit 1
            fi
        fi
        echo "PHP-FPM is running successfully."

        $SUDO rm -r /tmp/ioncube
        $SUDO rm /tmp/ioncube_loaders_lin_x86-64.tar.gz

        #Install Node.js
        if [ -n "$SUDO" ]; then
            curl -fsSL https://deb.nodesource.com/setup_22.x | $SUDO -E bash -
        else
            curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
        fi
        apt_install_noninteractive nodejs
        
        #Install and Configure Composer
        $SUDO php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
        $SUDO php composer-setup.php --quiet
        $SUDO mv composer.phar /usr/local/bin/composer

    elif [[ "$PKGMGR" == "yum" || "$PKGMGR" == "dnf" ]]; then

        PHP_FPM_CONF="/etc/php-fpm.d/www.conf"
        RPM_PHP_SETTINGS="/etc/php.ini"
        
    
        $SUDO dnf update -y

        $SUDO dnf install -y \
            epel-release \
            dnf-utils \
            curl \
            libzip \
            unzip \
            wget \
            policycoreutils-python-utils \
            mod_fcgid \
            tar \
            git

        $SUDO curl -LsSO https://r.mariadb.com/downloads/mariadb_repo_setup
        $SUDO chmod +x ./mariadb_repo_setup
        $SUDO ./mariadb_repo_setup --mariadb-server-version="mariadb-11.6.2" --skip-maxscale
        $SUDO dnf install MariaDB-server MariaDB-client MariaDB-backup galera-4 -y

        $SUDO systemctl start mariadb && $SUDO systemctl enable mariadb

        $SUDO dnf install -y https://rpms.remirepo.net/enterprise/remi-release-9.rpm
        $SUDO dnf module reset php -y
        $SUDO dnf module enable php:remi-8.2 -y

        $SUDO dnf install -y \
            php \
            php-fpm \
            php-common \
            php-process \
            php-curl \
            php-gd \
            php-mbstring \
            php-mysqlnd \
            php-opcache \
            php-xml \
            php-xmlrpc \
            php-pecl-imagick \
            php-zip

        

        #Configure PHP Settings
$SUDO sed -i 's/^upload_max_filesize = .*/upload_max_filesize = 10G/' $RPM_PHP_SETTINGS
$SUDO sed -i 's/^post_max_size = .*/post_max_size = 10G/' $RPM_PHP_SETTINGS
$SUDO sed -i 's/^max_execution_time = .*/max_execution_time = 360/' $RPM_PHP_SETTINGS

        #Verify PHP Settings
        #$SUDO grep -E 'upload_max_filesize|post_max_size|max_execution_time' $RPM_PHP_SETTINGS

        $SUDO sed -i 's/^user = apache/user = caddy/' $PHP_FPM_CONF
        $SUDO sed -i 's/^group = apache/group = caddy/' $PHP_FPM_CONF
        $SUDO sed -i 's/^listen.acl_users = .*/listen.acl_users = apache,nginx,caddy/' $PHP_FPM_CONF

        #$SUDO grep -E 'user = .*|group = .*|listen.acl_u' $PHP_FPM_CONF

        RPM_PHP_EXTDIR=$(php -r "echo ini_get('extension_dir').PHP_EOL;")

        # Download and extract IonCube in /tmp (using subshell to preserve current directory)
        (
            cd /tmp || exit 1
            $SUDO wget https://downloads.ioncube.com/loader_downloads/ioncube_loaders_lin_x86-64.tar.gz
            $SUDO tar -zxvf ioncube_loaders_lin_x86-64.tar.gz
        )

        $SUDO cp /tmp/ioncube/ioncube_loader_lin_8.2.so "$RPM_PHP_EXTDIR"

            #Update Config Files - add IonCube if not already present
            if ! grep -q "ioncube_loader" "$RPM_PHP_SETTINGS" 2>/dev/null; then
                echo "zend_extension=$RPM_PHP_EXTDIR/ioncube_loader_lin_8.2.so" | $SUDO tee -a $RPM_PHP_SETTINGS
            else
                echo "IonCube already configured in $RPM_PHP_SETTINGS"
            fi

            install_caddyserver

            # Reset-failed handles systemd rate-limit issues
            $SUDO systemctl reset-failed php-fpm 2>/dev/null || true
            sleep 2  # Brief delay to avoid rate-limiting
            $SUDO systemctl restart php-fpm
            $SUDO systemctl enable php-fpm

            # Verify PHP-FPM started successfully
            if ! systemctl is-active --quiet php-fpm; then
                echo "Warning: php-fpm failed to start after configuration"
                $SUDO systemctl reset-failed php-fpm 2>/dev/null || true
                sleep 5
                $SUDO systemctl start php-fpm
                if ! systemctl is-active --quiet php-fpm; then
                    echo "ERROR: php-fpm failed to start. Check 'systemctl status php-fpm' for details."
                    exit 1
                fi
            fi
            echo "PHP-FPM is running successfully."

            php -v

            $SUDO curl -fsSL https://rpm.nodesource.com/setup_22.x | $SUDO bash -
            $SUDO dnf install -y nodejs

            $SUDO php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
            $SUDO php composer-setup.php --quiet
            $SUDO mv composer.phar /bin/composer

            print_info "Required packages installed successfully."
    else
        echo "Unsupported Package Manager: $PKGMGR"
        exit 1
    fi

    if [[ $? -eq 0 ]]; then
        echo "Dependencies installed successfully."
    else
        echo "Failed to install dependencies."
        exit 1
    fi
}


install_caddyserver(){
    if [[ "$PKGMGR" == "apt" ]]; then
        echo -n "Installing CaddyServer... "
        $SUDO wget -q "https://github.com/caddyserver/caddy/releases/download/v${CADDY_VERSION}/caddy_${CADDY_VERSION}_linux_${CADDY_ARCH}.deb"
        apt_install_noninteractive "./caddy_${CADDY_VERSION}_linux_${CADDY_ARCH}.deb"

        if [ $? -eq 0 ]; then
            echo "CaddyServer installed."
        else
            echo "Failed to install CaddyServer."
            exit 1
        fi
        $SUDO rm -f "./caddy_${CADDY_VERSION}_linux_${CADDY_ARCH}.deb"
    elif [[ "$PKGMGR" == "yum" || "$PKGMGR" == "dnf" ]]; then
        $SUDO dnf install -y 'dnf-command(copr)'
        $SUDO dnf -y copr enable @caddy/caddy
        $SUDO dnf install -y caddy

        if [ $? -eq 0 ]; then
            echo "CaddyServer installed."
        else
            echo "Failed to install CaddyServer."
            exit 1
        fi
    else
        echo "Failed to install CaddyServer."
        exit 1
    fi
}


get_installer(){
    # Download the install repo file
    DEST_FILE="$INSTALL_DIR/installMultiportal"
    echo "Downloading the install repo file..."
    $SUDO curl -o "$DEST_FILE" "$REPO_URL"

    # Check if the file was downloaded successfully
    if [ $? -eq 0 ]; then
        # chmod +x "$DEST_FILE"
        echo "File downloaded successfully to $DEST_FILE."
    else
        echo "Failed to downloading the installer. Exiting..."
        exit 1
    fi

    # Make the downloaded file executable
    $SUDO chmod +x "$DEST_FILE"
    echo "The file has been made executable."
}

install_multiportal(){
    cd $INSTALL_DIR
       
    if [ -d "$WEB_DIR" ]; then
        echo "Directory '$WEB_DIR' exists. Skipping Installation"
    else
        echo "Directory '$WEB_DIR' does not exist. Proceeding with the installation"
        echo "Installing MultiPortal... on $WEB_DIR "
        $SUDO php "$INSTALL_DIR/installMultiportal" "$FQDN" ${MP_VERSION:+"$MP_VERSION"}
    fi
    
    if [ ! -d "$WEB_DIR" ]; then
        echo "Failed to install MultiPortal"
        exit 1
    fi

    $SUDO rm -f "$INSTALL_DIR/installMultiportal"
}

fix_permissions() {

# Determine the OS and set the default user
if grep -qi 'ubuntu' /etc/os-release || grep -qi 'debian' /etc/os-release; then
  default_user="www-data"
elif grep -qi "almalinux" /etc/os-release || grep -qi "rocky" /etc/os-release; then
  default_user="caddy"
else
  echo "Unsupported OS. Please specify the user manually."
  exit 1
fi

current_dir="/var/www/$(get_first_wwdir)"

# Check if the user is provided as an argument
current_user=$1

# Prompt for input if no user is provided
if [ -z "$current_user" ]; then
  read -p "Please enter the username of the current user (default: $default_user): " current_user
  if [ -z "$current_user" ]; then
    current_user="$default_user"
  fi
fi

# Check if the current user is in the default group if required
if [ "$current_user" != "$default_user" ] && ! groups "$current_user" | grep -qw "$default_user"; then
  echo "The current user is not in the $default_user group."
  echo "Please add the current user ($current_user) to the $default_user group and try again."
  exit 1
fi

# Set ownership recursively
echo "Setting ownership to $current_user:$default_user for all files and folders in $current_dir"
$SUDO chown -R "$current_user:$default_user" "$current_dir"

# Set permissions to 775 for directories and 664 for files
echo "Setting permissions to 775 for all directories"
$SUDO find "$current_dir" -type d -exec chmod 775 {} \;
echo "Setting permissions to 664 for all files"
$SUDO find "$current_dir" -type f -exec chmod 664 {} \;

# Set permissions to 775 for specific executable files
echo "Setting permissions to 775 for executable files"
$SUDO chmod +x "$current_dir/tools/permissionFix.sh"
$SUDO chmod +x "$current_dir/yii"
$SUDO chmod +x "$current_dir/init"

# Check if 'iso' directory exists, if not, create it
iso_dir="$current_dir/backend/web/iso"
if [ ! -d "$iso_dir" ]; then
  echo "Directory 'iso' does not exist. Creating it."
  $SUDO mkdir -p "$iso_dir"
fi

# Set ownership and permissions for specific backend directories
echo "Setting ownership to $current_user:$default_user for backend directories"
$SUDO chown -R "$current_user:$default_user" "$current_dir/backend/runtime/" "$current_dir/backend/web/assets/" "$iso_dir"
echo "Ensuring backend directories are writable"
$SUDO chmod -R 775 "$current_dir/backend/runtime/" "$current_dir/backend/web/assets/" "$iso_dir"

echo "Ownership and permissions updated successfully in $current_dir"
echo "If requested to do this before an update, you can now proceed with updating your MultiPortal Instance."
}

configure_permissions() {
    if [[ "$DISTRO" == "ubuntu" || "$DISTRO" == "debian" ]]; then
        fix_permissions www-data
    elif [[ "$DISTRO" == "almalinux" || "$DISTRO" == "rocky" ]]; then
        fix_permissions caddy
    else
        echo "Unsupported OS. Please specify the user manually."
        exit 1
    fi
}

setup_node() {
    echo "Setting up Node.js for $DISTRO..."
    # Use subshell to preserve current directory
    (
        cd "/var/www/$FQDN/websockets" || exit 1
        $SUDO npm cache clean --force
        $SUDO npm install
    )
}

setup_pm2(){
    echo "Installing PM2 globally..."
    PM2_LOG="/tmp/install_pm2.log"

    set +e  # Disable 'exit on error' temporarily

    $SUDO npm cache clean --force

    for attempt in {1..5}; do
        echo "Attempt $attempt: Installing PM2..." >> "$PM2_LOG"
        $SUDO timeout --kill-after=10s 2m bash -c "npm install pm2 -g" >> "$PM2_LOG" 2>&1
        install_pm2_status=$?

        if [ $install_pm2_status -eq 0 ]; then
            echo "PM2 installed successfully on attempt $attempt." >> "$PM2_LOG"
            break
        elif [ $install_pm2_status -eq 124 ]; then
            echo "Attempt $attempt: PM2 installation timed out after 2 minutes." >> "$PM2_LOG"
        else
            echo "Attempt $attempt: PM2 installation failed with exit code $install_pm2_status." >> "$PM2_LOG"
        fi
    done

    set -e  # Re-enable 'exit on error'
}



configure_sslcert() {
if [[ -n "${NOSSL:-}" ]]; then
    echo "NO cert provided as input, skipping this task and reverting to LetsEncrypt"
else
    echo "moving ssl cert to /var/lib/caddy folder..."
    $SUDO mv "$SSLCER" "$DSTCER"
    $SUDO mv "$SSLKEY" "$DSTKEY"
    $SUDO chown caddy:caddy "$DSTCER"
    $SUDO chown caddy:caddy "$DSTKEY"
fi
}

configure_caddy() {

    echo "Configuring CaddyServer..."

    if [[ "$PKGMGR" == "yum" || "$PKGMGR" == "dnf" ]]; then
        $SUDO mkdir -p /var/log/caddy
        $SUDO chown -R caddy:caddy /var/log/caddy
        $SUDO chmod 755 /var/log/caddy
    fi

    if [[ "$PKGMGR" == "apt" ]]; then
        cad_phpfastcgi="unix//var/run/php/php${PHP_VERSION_REQUIRED}-fpm.sock"
    elif [[ "$PKGMGR" == "yum" || "$PKGMGR" == "dnf" ]]; then
        cad_phpfastcgi="unix//run/php-fpm/www.sock"
    fi

if [[ -n "${NOSSL:-}" ]]; then
    if [[ -n "${HTTP_ONLY:-}" ]]; then
        CAD_FQDN="http://${FQDN}"
        echo "HTTP_ONLY mode: configuring Caddy for HTTP only (no TLS)"
    else
        CAD_FQDN="${FQDN}"
        echo "NO cert provided as input, configuring Caddy for LetsEncrypt"
    fi
    $SUDO cat > "$CADDYSERVER_CONF" << EOF
${CAD_FQDN} {
    @css path *.css
    header @css Content-Type text/css
    root * /var/www/${FQDN}/backend/web
    encode gzip
    file_server

    php_fastcgi ${cad_phpfastcgi} {
        index index.php
    }

    # Add headers
    header {
        Access-Control-Allow-Origin *
        Access-Control-Allow-Methods "GET, POST, OPTIONS"
        x-frame-options SAMEORIGIN
        Access-Control-Allow-Headers "Content-Type, Authorization"
    }

    # Error and access logs
    log {
        output file /var/log/caddy/${FQDN}.log
        level error
    }

    # PHP handling
    route / {
        try_files {path} {path}/ /index.php?{query}
        php_fastcgi ${cad_phpfastcgi} {
            env PHP_FCGI_MAX_REQUESTS 1000
        }
    }

    # Static files
    route / {
        file_server
    }

    # Reverse proxy to Node.js server
    reverse_proxy /wss* localhost:${CONSOLEPORT} {
        header_up Host {host}
        header_up X-Real-IP {remote}
    }
}
EOF
else
    CAD_FQDN="*.${FQDN#*.}"
    echo "Cert provided as input, configuring Caddy to use SSL cert provided"
    $SUDO cat > "$CADDYSERVER_CONF" << EOF
${CAD_FQDN} {
    tls $DSTCER $DSTKEY
    @css path *.css
    header @css Content-Type text/css
    root * /var/www/${FQDN}/backend/web
    encode gzip
    file_server

    php_fastcgi ${cad_phpfastcgi} {
        index index.php
    }

    # Add headers
    header {
        Access-Control-Allow-Origin *
        Access-Control-Allow-Methods "GET, POST, OPTIONS"
        x-frame-options SAMEORIGIN
        Access-Control-Allow-Headers "Content-Type, Authorization"
    }

    # Error and access logs
    log {
        output file /var/log/caddy/${FQDN}.log
        level error
    }

    # PHP handling
    route / {
        try_files {path} {path}/ /index.php?{query}
        php_fastcgi ${cad_phpfastcgi} {
            env PHP_FCGI_MAX_REQUESTS 1000
        }
    }

    # Static files
    route / {
        file_server
    }

    # Reverse proxy to Node.js server
    reverse_proxy /wss* localhost:${CONSOLEPORT} {
        header_up Host {host}
        header_up X-Real-IP {remote}
    }
}
EOF
fi

}

configure_mpservice(){
    echo "Configuring MultiPortal Service... " 
    # Create a new service file
    $SUDO tee "/etc/systemd/system/multiportal.service" > /dev/null << EOF
[Unit]
Description=MultiPortal Service
After=network.target

[Service]
User=root
Group=root
WorkingDirectory=${WEB_DIR}
ExecStart=/usr/bin/php ${WEB_DIR}/yii queue/listen --verbose
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF
    # Reload systemd
    $SUDO systemctl daemon-reload
    # Enable the service
    $SUDO systemctl enable multiportal.service
    # Start the service
    $SUDO systemctl start multiportal.service

    echo "MultiPortal Service configured successfully."
}

configure_firewall() {
    echo "checking if firewall-cmd exists,..."
    if command -v firewall-cmd &> /dev/null; then
        echo "firewall-cmd found, proceeding with firewall rules..."

        # Add HTTP and HTTPS services
        $SUDO firewall-cmd --permanent --add-service=https
        $SUDO firewall-cmd --permanent --add-service=http

        # Reload firewalld
        $SUDO firewall-cmd --reload

        echo "Firewall rules updated successfully."
    fi
}

configure_selinux() {

if command -v "getenforce" &>/dev/null; then
    echo "SELinux is Installed, starting configuration,..."
    selinux_status=$(getenforce)

    if [[ "$selinux_status" == "Enforcing" ]]; then

        # $SUDO setenforce 0
        echo "SELinux is enabled and set to 'Enforcing'."
        echo "Starting configuration,.."

        INSTALL_DIR="$(pwd)"
        POLICYCONF="$INSTALL_DIR/mp-policy.te"
        POLICYMOD="$INSTALL_DIR/mp-policy.mod"
        POLICYPP="$INSTALL_DIR/mp-policy.pp"

        $SUDO tee "$POLICYCONF" > /dev/null << EOF
module mp-policy 1.0;

require {
	type unconfined_service_t;
	type user_home_t;
	type httpd_sys_content_t;
	type init_t;
	type httpd_t;
	type mysqld_db_t;
	class file { append create open read setattr unlink write };
	class dir { add_name create remove_name setattr write };
	class unix_stream_socket connectto;
}

#============= httpd_t ==============

#!!!! This avc can be allowed using the boolean 'httpd_unified'
allow httpd_t httpd_sys_content_t:dir { add_name create remove_name setattr write };

#!!!! This avc can be allowed using the boolean 'httpd_unified'
allow httpd_t httpd_sys_content_t:file { append create setattr unlink write };
allow httpd_t unconfined_service_t:unix_stream_socket connectto;

#!!!! This avc can be allowed using the boolean 'httpd_read_user_content'
allow httpd_t user_home_t:file { open read };

#============= init_t ==============
allow init_t mysqld_db_t:file read;
EOF

    $SUDO checkmodule -M -m -o "$POLICYMOD" "$POLICYCONF"
    $SUDO semodule_package -o "$POLICYPP" -m "$POLICYMOD"
    $SUDO semodule -i "$POLICYPP"

    else
        echo "SELinux is not in 'Enforcing' mode. Current mode: $selinux_status"
        echo "Skipping SELinux configuration,.."
    fi

    return 0
fi


    
}


generate_ssh() {
    SSH_KEY_PATH="$HOME/.ssh/id_rsa.pub"

    # Check if the SSH public key file exists
    if [ -f "$SSH_KEY_PATH" ]; then
        echo "SSH public key exists. Contents are as follows:"
        cat "$SSH_KEY_PATH"
    else
        echo "SSH public key does not exist. Generating a new SSH key pair..."
        # Create the .ssh directory if it doesn't exist
        mkdir -p "$HOME/.ssh"
        # Generate a new SSH key pair
        ssh-keygen -t rsa -b 4096 -f "$HOME/.ssh/id_rsa" -N ""
        echo "New SSH key pair generated. Public key contents are as follows:"
        cat "$SSH_KEY_PATH"
    fi
}

copy_pubkey() {
    echo "Processing parameter -n:"
    for SERVER in "${VALUES[@]}"; do
        echo "Copying the SSH key to the server $SERVER..., please type yes and input password when prompted"
        ssh-copy-id -i "$SSH_KEY_PATH" "$USER@$SERVER"

        if [ $? -eq 0 ]; then
            echo "ssh-copy-id on $SERVER was successful!"
        else
            echo "ssh-copy-id on $SERVER failed. Please check your connection and credentials."
        fi
    done
}

configure_visudo() {
    echo "Configuring sudoers file on this node $(get_ip)..., please type yes and input password when prompted"
    # Use drop-in file instead of modifying /etc/sudoers directly (safer)
    echo "$USER ALL=(ALL) NOPASSWD: ALL" | $SUDO tee "/etc/sudoers.d/$USER" > /dev/null
    $SUDO chmod 440 "/etc/sudoers.d/$USER"
    CONFIG="echo '$USER ALL=(ALL) NOPASSWD: ALL' | sudo tee /etc/sudoers.d/$USER > /dev/null && sudo chmod 440 /etc/sudoers.d/$USER"
    echo "sudoers configuration on $HOSTNAME was successful!"
    for SERVER in "${VALUES[@]}"; do
        echo "Configuring sudoers file on $SERVER..., please type yes and input password when prompted"
        ssh -t "$USER@$SERVER" "$CONFIG"
        if [ $? -eq 0 ]; then
            echo "sudoers configuration on $SERVER was successful!"
        else
            echo "sudoers configuration on $SERVER failed. Please check your connection and credentials."
        fi
    done
}

# Function to validate an IP address
is_valid_ip() {
    local ip=$1
    local regex="^([0-9]{1,3}\.){3}[0-9]{1,3}$"
    
    if [[ $ip =~ $regex ]]; then
        # Check if each part of the IP is between 0 and 255
        IFS='.' read -r -a octets <<< "$ip"
        for octet in "${octets[@]}"; do
            if ((octet < 0 || octet > 255)); then
                return 1
            fi
        done
        return 0
    else
        return 1
    fi
}

get_ip() {
    # Fetch the IPv4 address of the active network interface
    ip_address=$(ip -4 addr show scope global | grep -oP '(?<=inet\s)\d+(\.\d+){3}')

    # Check if an IP address was found
    if [ -z "$ip_address" ]; then
        echo "No active IP address found."
        exit 1
    else
        echo "$ip_address"
    fi

}

get_first_wwdir() {

    TARGET_DIR="/var/www/"
    for dir in "$TARGET_DIR"/*.*; do
        if [ -d "$dir" ]; then
            echo "${dir##"$TARGET_DIR"/}"
            break
        fi
    done

}

create_mariadblogdir() {
    echo "Creating MariaDB log directory"
    $SUDO mkdir /var/log/mariadb
    $SUDO chown mysql:mysql /var/log/mariadb

    if [ $? -eq 0 ]; then
        echo "MariaDB log directory created successfully"
    else
        echo "MariaDB log directory creation failed."
    fi
}

configure_mariabackup() {

$SUDO mariadb -u root -e "
CREATE USER IF NOT EXISTS 'mariabackup'@'%' IDENTIFIED BY '${MARIABPASS}';
GRANT RELOAD, LOCK TABLES, PROCESS, REPLICATION CLIENT, CREATE TABLESPACE ON *.* TO 'mariabackup'@'%';
CREATE USER IF NOT EXISTS 'mariabackup'@'localhost' IDENTIFIED BY '${MARIABPASS}';
GRANT RELOAD, LOCK TABLES, PROCESS, REPLICATION CLIENT, CREATE TABLESPACE ON *.* TO 'mariabackup'@'localhost';
FLUSH PRIVILEGES;
"


if [ $? -eq 0 ]; then
    echo "Mariabackup user created successfully"
else
    echo "Mariabackup user creation failed."
fi

}

configure_galera_primary() {
    
    WWWFQDN=$(get_first_wwdir)
    NODE1_WWWDIR=/var/www/$WWWFQDN
    NODE1_ENVFILE=$NODE1_WWWDIR/.env

    echo "Configuring MariaDB Server Configuration file on $HOSTNAME"

    $SUDO tee -a /etc/mysql/mariadb.conf.d/50-server.cnf > /dev/null <<EOT
log_warnings=2
log_error=/var/log/mariadb/mariadb.err
general_log = 1
general_log_file = /var/log/mariadb/mariadb.log

[mariabackup]
user=mariabackup
password='$MARIABPASS'
databases-exclude=lost+found
EOT

    echo "Configuring MariaDB Galera Configuration file on $HOSTNAME"

$SUDO tee /etc/mysql/mariadb.conf.d/60-galera.cnf > /dev/null <<EOT
#
# * Galera-related settings
#
# See the examples of server wsrep.cnf files in /usr/share/mysql
# and read more at https://mariadb.com/kb/en/galera-cluster/

[galera]
# Mandatory settings
wsrep_on                 = ON
wsrep_cluster_name       = "galera_cluster"
wsrep_cluster_address    = "gcomm://$NODE1_IP,$NODE2_IP,$NODE3_IP"
wsrep_allowlist   = "$NODE1_IP,$NODE2_IP,$NODE3_IP"
wsrep_provider = /usr/lib/galera/libgalera_smm.so
wsrep_provider_options = 'gcache.size=2G;gcs.fc_limit=128'
binlog_format            = row
default_storage_engine   = InnoDB
innodb_autoinc_lock_mode = 2

# Allow server to accept connections on all interfaces.
bind-address = 0.0.0.0

# Optional settings
wsrep_slave_threads = 1
innodb_flush_log_at_trx_commit = 0
wsrep_sst_auth = "mariabackup:${MARIABPASS}"
wsrep_sst_method = mariabackup
wsrep_node_address = $NODE1_IP
wsrep_node_name="${HOSTNAME}"
wsrep_sst_receive_address= $NODE1_IP
EOT


    echo "Stopping MariaDB Service on $HOSTNAME"
    $SUDO systemctl stop mariadb.service
    echo "Bootstrapping New Galera Cluster"
    $SUDO galera_new_cluster

    if [ $? -eq 0 ]; then
        echo "Primary Node configured successfully"
    else
        echo "Primary Node configuration on $SERVER failed."
    fi

}

configure_galera_nodes() {
    WWWFQDN=$(get_first_wwdir)
    NODE1_WWWDIR=/var/www/$WWWFQDN
    NODE1_ENVFILE=$NODE1_WWWDIR/.env
    source <(grep 'DB_PASS=' $NODE1_ENVFILE)

for SERVER in "${VALUES[@]}"; do
echo "Configuring $SERVER"
NODE_WWWDIR=/var/www/$(ssh $USER@$SERVER "$(declare -f get_first_wwdir); get_first_wwdir")
NODE_ENVFILE=$NODE_WWWDIR/.env


#ssh $USER@$SERVER "grep 'DB_PASS=' $NODE_ENVFILE"


echo "Updating $NODE_ENVFILE on $SERVER"
ssh $USER@$SERVER "sudo sed -i 's/^DB_PASS=.*/DB_PASS=$DB_PASS/' $NODE_ENVFILE"

echo "Creating Log Directory on $SERVER"
ssh $USER@$SERVER "bash -c '$(declare -f create_mariadblogdir); create_mariadblogdir'"

ssh $USER@$SERVER "sudo mariadb -u root -e 'DROP DATABASE multiportal;'"

echo "Stopping services on $SERVER"
ssh $USER@$SERVER "sudo systemctl stop caddy.service"
ssh $USER@$SERVER "sudo systemctl stop multiportal.service"
ssh $USER@$SERVER "sudo systemctl stop mariadb.service"

echo "Configuring MariaDB Server Configuration file on $SERVER"

ssh $USER@$SERVER bash <<EOF
$SUDO tee -a /etc/mysql/mariadb.conf.d/50-server.cnf > /dev/null <<EOCONFIG
log_warnings=2
log_error=/var/log/mariadb/mariadb.err
general_log = 1
general_log_file = /var/log/mariadb/mariadb.log

[mariabackup]
user=mariabackup
password='$MARIABPASS'
databases-exclude=lost+found
EOCONFIG
EOF

echo "Configuring MariaDB Galera Configuration file on $SERVER"

ssh $USER@$SERVER bash <<EOF
$SUDO tee -a /etc/mysql/mariadb.conf.d/60-galera.cnf > /dev/null <<EOCONFIG
#
# * Galera-related settings
#
# See the examples of server wsrep.cnf files in /usr/share/mysql
# and read more at https://mariadb.com/kb/en/galera-cluster/

[galera]
# Mandatory settings
wsrep_on                 = ON
wsrep_cluster_name       = "galera_cluster"
wsrep_cluster_address    = "gcomm://$NODE1_IP,$NODE2_IP,$NODE3_IP"
wsrep_allowlist   = "$NODE1_IP,$NODE2_IP,$NODE3_IP"
wsrep_provider = /usr/lib/galera/libgalera_smm.so
wsrep_provider_options = 'gcache.size=2G;gcs.fc_limit=128'
binlog_format            = row
default_storage_engine   = InnoDB
innodb_autoinc_lock_mode = 2

# Allow server to accept connections on all interfaces.
bind-address = 0.0.0.0

# Optional settings
wsrep_slave_threads = 1
innodb_flush_log_at_trx_commit = 0
wsrep_sst_auth = "mariabackup:${MARIABPASS}"
wsrep_sst_method = mariabackup
wsrep_node_address = $SERVER
wsrep_node_name="${HOSTNAME}"
wsrep_sst_receive_address= $SERVER
EOCONFIG
EOF

echo "Starting MariaDB service"

ssh $USER@$SERVER "sudo systemctl restart mariadb.service"

echo "Confirming Galera Process"
ssh $USER@$SERVER bash <<EOF
$SUDO ps -f -u mysql
$SUDO mariadb -u root -e "show global status like 'wsrep_cluster_size';"
EOF

echo "Starting Multiportal and Caddy service"

ssh $USER@$SERVER "sudo systemctl restart multiportal"
ssh $USER@$SERVER "sudo systemctl restart caddy"

        if [ $? -eq 0 ]; then
            echo "Node configuration on $SERVER was successful!"
        else
            echo "Node configuration on $SERVER failed. Please check your connection and credentials."
        fi
    done

}


install_mp(){

if [[ -n "${CER:-}" || -n "${KEY:-}" ]]; then
    SSLCER="$(cd "$(dirname "$CER")" && pwd)/${CER##*/}"
    SSLKEY="$(cd "$(dirname "$KEY")" && pwd)/${KEY##*/}"
fi


accept_eula

WEB_DIR="/var/www/$FQDN"
DISTRO=$(get_linux_distribution)
PKGMGR=$(get_package_manager)

print_info "Installing Required Packages"
install_dependencies >> "$LOG_FILE" 2>&1 &
DEP_PID=$!
show_loading_with_timer $DEP_PID
wait $DEP_PID
DEP_STATUS=$?
if [ $DEP_STATUS -ne 0 ]; then
    print_error "Failed to install required packages (exit code: $DEP_STATUS)"
    print_error "Check log file for details: $LOG_FILE"
    print_error "Last 20 lines of log:"
    tail -20 "$LOG_FILE" >&2
    exit 1
fi

print_info "Disabling Apache2 if Installed"
disable_apache2 >> "$LOG_FILE" 2>&1 &
show_loading_with_timer $!
wait $!

print_info "Downloading Multiportal Installer"
get_installer >> "$LOG_FILE" 2>&1 &
GET_PID=$!
show_loading_with_timer $GET_PID
wait $GET_PID
if [ $? -ne 0 ]; then
    print_error "Failed to download Multiportal installer"
    print_error "Check log file for details: $LOG_FILE"
    tail -20 "$LOG_FILE" >&2
    exit 1
fi

print_info "Installing Multiportal"
install_multiportal >> "$LOG_FILE" 2>&1 &
INST_PID=$!
show_loading_with_timer $INST_PID
wait $INST_PID
if [ $? -ne 0 ]; then
    print_error "Failed to install Multiportal"
    print_error "Check log file for details: $LOG_FILE"
    tail -20 "$LOG_FILE" >&2
    exit 1
fi

print_info "Configuring Permissions"
configure_permissions >> "$LOG_FILE" 2>&1 &
show_loading_with_timer $!
wait $!

print_info "Setting up and configuring node"
setup_node >> "$LOG_FILE" 2>&1 &
show_loading_with_timer $!
wait $!

print_info "Configuring PM2"
setup_pm2 >> "$LOG_FILE" 2>&1 &
show_loading_with_timer $!
wait $!

if which pm2 > /dev/null 2>&1; then
    print_info "PM2 Has successfully been installed."
else
    print_error "PM2 was not installed."
fi

$SUDO systemctl stop caddy

print_info "Configuring SSLCERT"
configure_sslcert >> "$LOG_FILE" 2>&1 &
show_loading_with_timer $!
wait $!

print_info "Configuring Caddy"
configure_caddy >> "$LOG_FILE" 2>&1 &
show_loading_with_timer $!
wait $!

print_info "Configuring Firewall-CMD if Installed"
configure_firewall >> "$LOG_FILE" 2>&1 &
show_loading_with_timer $!
wait $!

print_info "Configuring SELinux if Installed"
configure_selinux >> "$LOG_FILE" 2>&1 &
show_loading_with_timer $!
wait $!

print_info "Disabling Apache2 if Installed"
disable_apache2 >> $LOG_FILE 2>&1 &
show_loading_with_timer $!
wait $!

sudo systemctl start caddy

print_info "Configuring Multiportal Service"
configure_mpservice >> "$LOG_FILE" 2>&1 &
show_loading_with_timer $!
wait $!

systemctl restart caddy

wait $!
if [ -f "$INSTALL_DIR/installMultiportal" ]; then
    rm -f "$INSTALL_DIR/installMultiportal"
fi

print_info "---------------------------------------"
print_info  "Installation has completed"
print_info  "---------------------------------------"
print_info  "To view your instance, visit http://$FQDN"
print_info  "The installed directory of your instance is $WEB_DIR"
print_info  "Caddyfile is located at $CADDYSERVER_CONF"
print_info  "---------------------------------------"

print_info "$APP_NAME installation finished successfully!"

END_TIME=$(date +%s)
ELAPSED_TIME=$((END_TIME - START_TIME))
ELAPSED_SECONDS=$(printf "%.0f" "$ELAPSED_TIME")
MINUTES=$((ELAPSED_SECONDS / 60))
SECONDS=$((ELAPSED_SECONDS % 60))
print_info "Elapsed time: $MINUTES minutes and $SECONDS seconds ($ELAPSED_TIME seconds total)"
print_info "For more details, see log file: $LOG_FILE"

}

start_prepnodes(){
    # Split and count the values for parameter -p using read with explicit delimiter
    IFS=',' read -ra VALUES <<< "$NODES"

    print_info "Configuring SSH,.. please type yes and input password when prompted"
    generate_ssh

    print_info "Copying Keys on nodes,.. please type yes and input password when prompted"
    copy_pubkey 

    print_info "Configuring sudoers file,.. please type yes and input password when prompted"
    configure_visudo
}

start_confignodes(){
    # Split and count the values for parameter -c using read with explicit delimiter
    IFS=',' read -ra VALUES <<< "$NODES"
    
    NODE1_IP=$(get_ip)

    if ! is_valid_ip "$NODE1_IP"; then
        echo "Error: '$NODE1_IP' is not a valid IP address."
        exit 1
    fi

    NODE2_IP=${VALUES[0]}
    NODE3_IP=${VALUES[1]}

    # Generate a secure random password for MariaDB backup user
    export MARIABPASS="$(openssl rand -base64 16 | tr -dc 'a-zA-Z0-9' | head -c 16)"

    create_mariadblogdir
    configure_mariabackup
    configure_galera_primary

    configure_galera_nodes

}


#############################################################
# MAIN Execution                                            #
#############################################################

# Initialize sudo handling first - must be before any sudo commands
setup_sudo

NODES=""

if [ -e "$LOG_FILE" ]; then
    echo "The file '$LOG_FILE' exists."
    $SUDO chown "$USER:$USER" "$LOG_FILE"
fi


START_TIME=$(date +%s)
print_info "$(date '+%Y-%m-%d %H:%M:%S')"
initialize_log

PARAM1=false
PARAM2=false
PARAM3=false
PARAM4=false
PARAM5=false


export COMPOSER_ALLOW_SUPERUSER=1;

# Preprocess arguments to convert long options to short ones
for arg in "$@"; do
    shift
    case "$arg" in
        --fqdn) set -- "$@" "-f" ;;
        --prepnodes) set -- "$@" "-p" ;;
        --confignodes) set -- "$@" "-c" ;;
        --sslcert) set -- "$@" "-s" ;;
        --sslkey) set -- "$@" "-k" ;;
        --http-only) set -- "$@" "-H" ;;
        --help) set -- "$@" "-h" ;;
        *) set -- "$@" "$arg" ;;
    esac
done

# Pre-process long options (getopts only handles short flags)
_args=()
while [[ $# -gt 0 ]]; do
    case "$1" in
        --version)
            if [[ -n "${2:-}" && "$2" != -* ]]; then
                MP_VERSION="$2"
                shift 2
            else
                echo "Error: --version requires a value (e.g. --version 1.1.0)"
                exit 1
            fi
            ;;
        *) _args+=("$1"); shift ;;
    esac
done
set -- "${_args[@]+"${_args[@]}"}"

# Parse arguments using getopts
while getopts "f:p:c:s:k:hH" opt; do
    case "$opt" in
        f)  
            if [[ "$PARAM2" = true || "$PARAM3" = true ]]; then
                echo "Error: You cannot use fqdn with other parameters."
                exit 1
            fi
            PARAM1=true
            FQDN="$OPTARG"
            print_info "FQDN set from parameter, continuing..."
            ;;
        p)  
            if [[ "$PARAM1" = true || "$PARAM3" = true ]]; then
                echo "Error: You cannot use prepnode with other parameters."
                exit 1
            fi 
            PARAM2=true
            NODES="$OPTARG"
            print_info "NODES received from parameter, continuing..."
            ;;
        c)  
            if [[ "$PARAM1" = true || "$PARAM2" = true ]]; then
                echo "Error: You cannot use confignodes with other parameters."
                exit 1
            fi 
            PARAM3=true
            NODES="$OPTARG"
            print_info "NODES received from parameter, continuing..."
            ;;
        s)  
            if [[ "$PARAM2" = true || "$PARAM3" = true ]]; then
                echo "Error: You can use sslcert parameter ONLY with fqdn and sslkey paremeters."
                exit 1
            fi 
            PARAM4=true
            CER="$OPTARG"
            ;;
        k)  
            if [[ "$PARAM2" = true || "$PARAM3" = true  ]]; then
                echo "Error: You can use sslkey parameter ONLY with fqdn and sslcert paremeters."
                exit 1
            fi
            PARAM5=true
            KEY="$OPTARG"
            ;;
        H)
            if [[ "$PARAM2" = true || "$PARAM3" = true ]]; then
                echo "Error: You cannot use http-only with cluster parameters."
                exit 1
            fi
            HTTP_ONLY=true
            print_info "HTTP_ONLY mode enabled, Caddy will serve HTTP only"
            ;;
        h) 
            print_usage
            exit 0
            ;;
        *) 
            print_usage
            exit 1
            ;;
    esac
done

# validate_input

# install_mp_onnodes

# configure_galera_nodes

if [[ $PARAM1 == true && $PARAM2 == false && $PARAM3 == false && $PARAM4 == false && $PARAM5 == false ]]; then
    if is_root_user; then
        echo "Proceeding with root-only (sudo) operations..."
    else
        echo "Use FQDN parameter with sudo."
        exit 1
    fi
    export DEBIAN_FRONTEND=noninteractive
    NOSSL=true
    install_mp
    exit 0
fi

if [[ $PARAM1 == true && $PARAM2 == false && $PARAM3 == false && $PARAM4 == true && $PARAM5 == true ]]; then
    if is_root_user; then
        echo "Proceeding with root-only (sudo) operations..."
    else
        echo "Use FQDN parameter with sudo."
        exit 1
    fi
    export DEBIAN_FRONTEND=noninteractive
    install_mp
    exit 0
fi

if [[ $PARAM2 == true && $PARAM1 == false && $PARAM3 == false && $PARAM4 == false && $PARAM5 == false ]]; then
    if is_root_user; then
        echo "Error: this operation must be run with sudo"
        exit 1
    else
        echo "Proceeding with user-only ($USER) operations..."
    fi
    start_prepnodes
    exit 0
fi

if [[ $PARAM3 == true && $PARAM2 == false && $PARAM1 == false && $PARAM4 == false && $PARAM5 == false ]]; then
    if is_root_user; then
        echo "Error: this operation must be run with sudo"
        exit 1
    else
        echo "Proceeding with user-only ($USER) operations..."
    fi
    start_confignodes
    exit 0
fi

