#!/bin/bash
export COMPOSER_ALLOW_SUPERUSER=1;
# Ensure the script is run as root
if [ "$(id -u)" != "0" ]; then
   echo "This script must be run as root" 1>&2
   exit 1
fi
# Function to generate a random string
generate_random_string() {
    echo "$(openssl rand -base64 4 | tr -dc 'a-zA-Z0-9' | head -c 5)"
}

# Loader function
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"
}

echo "---------------------------------------------"
echo "          Welcome to MultiPortal!"
echo "---------------------------------------------"
echo "          Version: 1.0.0"
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 ""

# Prompt the user for confirmation
while true; do
    read -p "Do you agree to the EULA agreement? (yes/no): " response
    case "$response" in
        [Yy][Ee][Ss])
            echo "Thank you for agreeing to the EULA. Proceeding..."
            break
            ;;
        [Nn][Oo])
            echo "You did not agree to the EULA. Exiting..."
            exit 1
            ;;
        *)
            echo "Invalid input. Please type 'yes' or 'no'."
            ;;
    esac
done
# Check if the directory exists
installationDirectory=$(pwd)

# Set the CaddyServer version and architecture
CADDY_VERSION="2.7.6"
CADDY_ARCH="amd64"
REPO_URL="https://downloads.multiportal.io/installer/mpInstallation"

# Main Script Execution
HOST_NAME=$1
# Check if the hostname is valid
if [ -z "$HOST_NAME" ]; then
    read -p "What is the FQDN you're going to use?: " HOST_NAME < /dev/tty
fi
if [ -z "$HOST_NAME" ]; then
    echo "Hostname cannot be empty. Exiting..."
    exit 1
fi
#read -p "Do you want to harden the MySQL instance? (yes/no): " hardenMysql
hardenMysql="no"

# Common Variables
ENV_NAME=".env"
WEB_DIR="/var/www/$HOST_NAME"
CADDYSERVER_CONF="/etc/caddy/Caddyfile"

DB_HOST=localhost
DB_NAME=multiportal
DB_USER=multiportal
RANDOM_STRING=$(generate_random_string)  # Changed from RANDOM to RANDOM_STRING
DB_PASS=$(openssl rand -base64 12) # Generates a secure password. Adjust length
ROOT_PASS=$(openssl rand -base64 12) # Generate a secure root password
PHPVERSION=8.2
CONSOLEPORT=8081
COOKIE_VALIDATION_KEY=$(openssl rand -base64 12)

get_installer(){
    # Check if curl is installed
    if ! command -v curl >/dev/null 2>&1; then
        echo "curl is not installed. Installing curl..."

        # Install curl
        apt install -y curl >/dev/null >/dev/null 2>&1 &
        show_loader $!
        wait $!

        # Verify installation
        if ! command -v curl >/dev/null 2>&1; then
            echo "Failed to install curl. Exiting..."
            exit 1
        fi
        echo "curl installed successfully."
    fi

    # Download the install repo file
    DEST_FILE="$installationDirectory/installMultiportalRepo"
    echo "Downloading the install repo file..."
    curl -o "$DEST_FILE" "$REPO_URL" >/dev/null 2>&1

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

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

# Function to install dependencies and verify installation
install_dependencies() {
    local success=true
    echo "Installing dependencies... "
    add-apt-repository -y ppa:ondrej/php >/dev/null 2>&1 &
    show_loader $!
    wait $!
    apt update >/dev/null 2>&1 &
    show_loader $!
    wait $!
    apt install -y debian-keyring debian-archive-keyring apt-transport-https unzip git >/dev/null 2>&1 &
    show_loader $!
    wait $!
    echo -n "Installing libapache2-mod-fcgid... "
    apt install -y libapache2-mod-fcgid >/dev/null 2>&1 &
    show_loader $!
    wait $!
    if [ $? -eq 0 ]; then
        echo "libapache2-mod-fcgid installed."
    else
        echo "Failed to install libapache2-mod-fcgid."
        success=false
    fi
    echo -n "Installing software-properties-common... "
    apt install -y software-properties-common >/dev/null 2>&1 &
    show_loader $!
    wait $!
    if [ $? -eq 0 ]; then
        echo "software-properties-common installed."
    else
        echo "Failed to install software-properties-common."
        success=false
    fi
    echo -n "Installing mariadb-server... "
    apt install -y mariadb-server >/dev/null 2>&1 &
    show_loader $!
    wait $!
    if [ $? -eq 0 ]; then
        echo "mariadb-server installed."
    else
        echo "Failed to install mariadb-server."
        success=false
    fi
    echo -n "Installing PHP... "
    apt install -y 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-xmlrpc php8.2-imagick php8.2-zip >/dev/null 2>&1 &
    show_loader $!
    wait $!
    if [ $? -eq 0 ]; then
        echo "PHP Installed."
        if command -v php$PHPVERSION &> /dev/null; then
            PHP_CONFIG_FILE="/etc/php/$PHPVERSION/fpm/php.ini"
            echo "Updating PHP configuration file $PHP_CONFIG_FILE..."
            if [ -f "$PHP_CONFIG_FILE" ]; then
                # Adjust upload related settings
                sed -i "s/^;*upload_max_filesize = .*/upload_max_filesize = 10G/" "$PHP_CONFIG_FILE"
                sed -i "s/^;*post_max_size = .*/post_max_size = 10G/" "$PHP_CONFIG_FILE"
                sed -i "s/^;*max_execution_time = .*/max_execution_time = 360/" "$PHP_CONFIG_FILE"
                sed -i "s/^;*max_file_uploads = .*/max_file_uploads = 999/" "$PHP_CONFIG_FILE"
                echo "PHP configuration updated successfully."
            else
                echo "Warning: PHP configuration file not found at $PHP_CONFIG_FILE. Upload related settings were not updated."
            fi
        fi
        systemctl restart php$PHPVERSION-fpm >/dev/null 2>&1 &
        show_loader $!
        wait $!
        echo "PHP-FPM service restarted successfully."
    else
        echo "Failed to install PHP."
        success=false
    fi
    if command -v node >/dev/null 2>&1; then
        echo "Node is already installed."
    else
        echo -n "Installing Node... "
        (curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - & apt install -y nodejs npm) >/dev/null 2>&1 &
        show_loader $!
        wait $!
        if [ $? -eq 0 ]; then
            echo "Node has been installed."
        else
            echo "Failed to install Node."
            success=false
        fi
    fi

    if [ "$success" = false ]; then
        echo "One or more dependencies failed to install. Exiting..."
        exit 1
    fi
    echo "Dependencies have been installed!"
    if [ "$success" = false ]; then
        echo "One or more dependencies failed to install. Exiting..."
        exit 1
    fi
}

install_caddyserver(){
    echo -n "Installing CaddyServer... "
    wget -q "https://github.com/caddyserver/caddy/releases/download/v${CADDY_VERSION}/caddy_${CADDY_VERSION}_linux_${CADDY_ARCH}.deb"
    apt install "./caddy_${CADDY_VERSION}_linux_${CADDY_ARCH}.deb" >/dev/null 2>&1 &
    show_loader $!
    wait $!
    if [ $? -eq 0 ]; then
        echo "CaddyServer installed."
    else
        echo "Failed to install CaddyServer."
        success=false
    fi
    unlink "./caddy_${CADDY_VERSION}_linux_${CADDY_ARCH}.deb"
}

# Function to configure Ioncube
download_ioncube(){
    echo "Configuraing Ioncube... " &
    show_loader $!
    extension_dir=$(php -r "echo ini_get('extension_dir');") 
    cd /tmp
    wget https://downloads.ioncube.com/loader_downloads/ioncube_loaders_lin_x86-64.tar.gz >/dev/null 2>&1
    tar -zxvf ioncube_loaders_lin_x86* >/dev/null 2>&1
    cd ioncube/
    sudo cp /tmp/ioncube/ioncube_loader_lin_8.2.so "$extension_dir/ioncube_loader_lin_8.2.so" >/dev/null 2>&1
    # Clean up downloaded files
    rm -f /tmp/ioncube_loaders_lin_x86-64.tar.gz >/dev/null 2>&1
    rm -rf /tmp/ioncube/ >/dev/null 2>&1
    wait $!
    echo "Ioncube configured successfully."
}

# Configure Ioncube
configure_ioncube() {
    extension_dir=$(php -r "echo ini_get('extension_dir');")
    
    # Check if the file contains any existing zend_extension directives
    if ! sudo grep -q '^zend_extension = ' "$1"; then
        # If not, append the ionCube loader configuration at the end of the file
        echo "zend_extension = $extension_dir/ioncube_loader_lin_8.2.so" | sudo tee -a "$1" >/dev/null
    else
        # If the file already contains zend_extension directives, replace the commented out line
        sudo sed -i "s|^;ioncube loader configuration|zend_extension = $extension_dir/ioncube_loader_lin_8.2.so|" "$1"
    fi
}

install_composer (){
    # Print message indicating the start of Composer installation
    echo "Installing Composer... "

    # Download Composer installer
    php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" >/dev/null 2>&1
    if [ $? -ne 0 ]; then
        echo "Failed to download Composer installer. Check your internet connection or try again later."
        exit 1
    fi

    # Verify the integrity of the downloaded installer
    EXPECTED_CHECKSUM="$(php -r 'copy("https://composer.github.io/installer.sig", "php://stdout");')"
    ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")"

    if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]
    then
        >&2 echo 'ERROR: Invalid installer checksum'
        rm composer-setup.php
        exit 1
    fi


    if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]; then
        echo "Composer installer integrity check failed. Try running the script again."
        exit 1
    fi

    # Run Composer installer
    php composer-setup.php --quiet >/dev/null 2>&1
    if [ $? -ne 0 ]; then
        echo "Composer setup failed. Check the composer-setup.php file for details."
        exit 1
    fi

    # Remove the installer script
    php -r "unlink('composer-setup.php');" >/dev/null 2>&1

    # Move Composer executable to /usr/local/bin
    sudo mv composer.phar /usr/local/bin/composer >/dev/null 2>&1
    if [ $? -eq 0 ]; then
        echo "Composer installed successfully"
    else
        echo "Failed to move Composer executable to /usr/local/bin. Check your permissions."
        exit 1
    fi
}

install_multiportal(){
    cd $installationDirectory
    echo "Installing MultiPortal... "
    php "$installationDirectory/installMultiportalRepo" "$HOST_NAME"

    if [ ! -d "$WEB_DIR" ]; then
        echo "Failed to install MultiPortal"
        exit 1
    fi

    # Run the yii generate-api-key command
    echo "Running 'yii generate-api-key true' in $WEB_DIR..."
    cd "$WEB_DIR"
    if [ -f "yii" ]; then
        sudo -u www-data php yii generate-api-key true
    else
        echo "Error: 'yii' command not found in $WEB_DIR."
        exit 1
    fi
    unlink "$installationDirectory/installMultiportalRepo"    
}


configure_service(){
    echo "Configuring MultiPortal Service... " 
    # Create a new service file
    cat > "/etc/systemd/system/multiportal.service" << 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
    systemctl daemon-reload
    # Enable the service
    systemctl enable multiportal.service
    # Start the service
    systemctl start multiportal.service

    echo "MultiPortal Service configured successfully."
}

# Function to configure CaddyServer
configure_caddy() {
    echo "Configuring CaddyServer..."
    cat > "$CADDYSERVER_CONF" << EOF
${HOST_NAME} {
    @css path *.css
    header @css Content-Type text/css
    root * /var/www/${HOST_NAME}/backend/web
    encode gzip
    file_server

    php_fastcgi unix//var/run/php/php${PHPVERSION}-fpm.sock {
        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/${HOST_NAME}.log
        level error
    }

    # PHP handling
    route / {
        try_files {path} {path}/ /index.php?{query}
        php_fastcgi unix//var/run/php/php8.2-fpm.sock {
            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
}

# Function to clean up the SSH key file
clean_up_ssh_key(){
    unset GIT_SSH_COMMAND
    if [ -f "$KEY_FILE" ]; then
        rm -f "$KEY_FILE"
        echo "SSH key file cleaned up."
    fi
}

setup_node() {
    # Set the PM2 directory path
    PM2_DIR="/var/www/.pm2"

    # Check if the directory exists
    if [ ! -d "$PM2_DIR" ]; then
        echo "Creating directory for PM2 at $PM2_DIR"
        
        # Create the directory with permissions
        mkdir -p "$PM2_DIR"
        chmod 0775 "$PM2_DIR"

        # Set ownership to www-data user and group
        chown www-data:www-data "$PM2_DIR"

        echo "PM2 directory created successfully with permissions and ownership set."
    else
        echo "PM2 directory already exists at $PM2_DIR"
    fi
    echo "Setting up Node... " 
    cd "$WEB_DIR/websockets"
    sudo npm install >/dev/null 2>&1 &
    show_loader $!
    wait $!
    sudo npm install pm2 -g >/dev/null 2>&1 &
    show_loader $!
    wait $!
    echo "Node setup completed successfully."
}


get_installer
install_dependencies
install_caddyserver
install_composer
# Install ioncube and configure PHP CLI and FPM configuration file
download_ioncube
configure_ioncube "/etc/php/8.2/cli/php.ini"
configure_ioncube "/etc/php/8.2/fpm/php.ini"
systemctl restart php8.2-fpm

install_multiportal

# Setup Node
setup_node
systemctl stop caddy
configure_caddy
systemctl start caddy
configure_service

wait $!
if [ -f "$installationDirectory/installMultiportalRepo" ]; then
    rm -f "$installationDirectory/installMultiportalRepo"
fi

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


