##### 9/18
### FIXED

#!/bin/bash
# Fully Dynamic Multi-Geo HA WordPress for Debian 13
# Usage: ./deploy www.domain.com [/mnt/objectstore/.www.domain.com/]
# Must run as a normal user with sudo privileges. Fails if run as root.
# ==== FAIL IF RUN AS ROOT ====
if [[ $EUID -eq 0 ]]; then
    echo "Do NOT run this script as root. Use a normal user with sudo privileges."
    exit 1
fi
# Record start time
START_TIME=$(date +%s)
# === CONFIG ===

cd $HOME
PASSVER="0.57b"
AUTHOR="Gabe/IHN"
GALERA_CONF_FILE="/etc/mysql/mariadb.conf.d/60-galera.cnf"
GALERA_CLUSTER_NAME="HACluster"
SCRIPT_PATH="/usr/local/bin/maria-phoenix.sh"
SERVICE_PATH="/etc/systemd/system/maria-phoenix.service"
CONF_FILE="/etc/sysctl.d/99-disable-ipv6.conf"
WWW_USER="www-data"
NODE_HOSTNAME=$1
NODE_NAME=$(hostname -s)
NODE_NAME_CLUSTER=$(hostname -s).$(hostname -d)
WWW_NAME=$NODE_HOSTNAME
RANDOM_COCKPIT_USER=false
CUSTOM_ADMIN=""
USE_RANDOM_ADMIN=false
AUTOUPDATE_PLUGINS=true
ENABLE_CUSTOM_THEME=true
THEME_SLUG="kadence"
COMMENTS_ENABLED=false
RUN_SSL=false
PERMALINK_STRUCTURE='/%year%/%monthnum%/%day%/%postname%/'
PERMALINKS=true

# === RANDOMIZED OBJECT STORAGE PATH ===
rand_str=$(tr -dc 'A-Za-z0-9' </dev/urandom | head -c8)
OBJECT_STORAGE_PATH=${2:-"/mnt/objectstore/.${WWW_NAME}_${rand_str}"}

if [ "$RANDOM_COCKPIT_USER" = true ]; then
    ADMINUSER=$(tr -dc 'A-Za-z0-9' </dev/urandom | head -c8)
else
    ADMINUSER="adminuser"
fi
ADMINUSER_PASS=$(tr -dc 'A-Za-z0-9' </dev/urandom | head -c26)

# === ARGUMENT CHECK ===
if [[ -z "$NODE_HOSTNAME" ]]; then
    echo "Usage: $0 NODE_FQDN [/objectstore]"
    exit 1
fi

# ==== DETECT PUBLIC IP ====
NODE_IP=$(dig +short "$NODE_HOSTNAME" | head -n1)
if [[ -z "$NODE_IP" ]]; then
    echo "Failed to resolve $NODE_HOSTNAME"
    exit 1
fi
INTERFACE=$(ip -o -4 addr show | grep "$NODE_IP" | awk '{print $2}')

#### SUDO LOOP IS A GO!
sudo -v
while true; do sudo -v; sleep 60; done &
KEEP_SUDO_PID=$!
trap 'kill $KEEP_SUDO_PID' EXIT

# Detect gradient state from PASSVER
if [[ "$PASSVER" == *"std"* ]]; then
    GRADIENT_STATE=0
elif [[ "$PASSVER" == *"a"* ]]; then
    GRADIENT_STATE=1
elif [[ "$PASSVER" == *"b"* ]]; then
    GRADIENT_STATE=2
elif [[ "$PASSVER" == *"s"* ]]; then
    GRADIENT_STATE=3
else
    GRADIENT_STATE=0  # fallback → Standard
fi

# Define gradient presets
set_gradient_colors() {
    case $GRADIENT_STATE in
        0)  # Standard → Yellow to Blood Red
            R1=255; G1=255; B1=0
            R2=138; G2=3;   B2=3
            GRADIENT_NAME="Standard"
            ;;
        1)  # Alpha → Green to Cyan
            R1=0;   G1=255; B1=0
            R2=0;   G2=255; B2=255
            GRADIENT_NAME="Alpha"
            ;;
        2)  # Beta → Blue to Purple
            R1=0;   G1=0;   B1=255
            R2=128; G2=0;   B2=128
            GRADIENT_NAME="Beta"
            ;;
        3)  # Special → Magenta to Blood Red
            R1=255; G1=0;   B1=255
            R2=138; G2=3;   B2=3
            GRADIENT_NAME="Special"
            ;;
        *)
            R1=255; G1=255; B1=255
            R2=128; G2=128; B2=128
            GRADIENT_NAME="Fallback"
            ;;
    esac
}


# === Gradient toggle (4 states) ===
# 0 = Standard (Yellow → Blood Red)
# 1 = Alpha   (Green → Cyan)
# 2 = Beta    (Blue → Purple)
# 3 = Special (Magenta → Blood Red)
#GRADIENT_STATE=3

# Load the chosen gradient
set_gradient_colors

### PREFLIGHT
# Make sure it exists
sudo mkdir -p $OBJECT_STORAGE_PATH
sudo chown $WWW_USER:$WWW_USER $OBJECT_STORAGE_PATH
sudo locale-gen en_US.UTF-8
export LANG=en_US.UTF-8
locale
echo "Node Name: $NODE_NAME_CLUSTER"
echo "Node Hostname: $NODE_HOSTNAME"
echo "Detected IP: $NODE_IP"
echo "Detected interface: $INTERFACE"
echo "Using Object Storage Path: $OBJECT_STORAGE_PATH"
echo "web for visitors: $WWW_NAME"


# Install base packages
sudo apt update
sudo apt -y install lsb-release ca-certificates apt-transport-https wget gnupg2

# Add Sury PHP repo
sudo wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/php.list
sudo apt update

# Determine the latest PHP package available from Sury
LATEST_PHP=$(apt-cache search php-fpm | grep -E '^php[0-9]+\.[0-9]+-fpm' | sort -V | tail -1 | awk -F'-' '{print $1}')
echo "Latest PHP detected: $LATEST_PHP"

# Install your stack dynamically with latest PHP
sudo apt -y install \
    ufw nginx mariadb-server mariadb-client galera-4 \
    wget unzip curl jq keepalived rsync certbot python3-certbot-nginx \
    s3fs redis-server mc htop nload screen tmux byobu \
    cockpit cockpit-storaged cockpit-networkmanager \
    ${LATEST_PHP}-fpm ${LATEST_PHP}-mysql ${LATEST_PHP}-redis \
    ${LATEST_PHP}-curl ${LATEST_PHP}-xml ${LATEST_PHP}-imagick \
    ${LATEST_PHP}-mbstring ${LATEST_PHP}-zip ${LATEST_PHP}-gd ${LATEST_PHP}-intl

sudo  apt  update  -y
sudo  apt  upgrade  -y  

for svc in $(systemctl list-units --type=service | awk '/php[0-9]+\.[0-9]+-fpm\.service/ {print $1}'); do
    VER=$(echo "$svc" | grep -oP '[0-9]+\.[0-9]+')
    CONF="/etc/php/$VER/fpm/pool.d/www.conf"
    [ -f "$CONF" ] && (
        grep -q '^request_terminate_timeout' "$CONF" && \
        sudo sed -i "s/^request_terminate_timeout = .*/request_terminate_timeout = 120s/" "$CONF" || \
        echo "request_terminate_timeout = 120s" | sudo tee -a "$CONF" >/dev/null
    ) && sudo systemctl reload "$svc"
done
sudo mkdir -p  /var/www/.wp-cli/cache
sudo chown $WWW_USER:$WWW_USER -R /var/www/.wp-cli
echo "[*] Creating sysctl config to disable IPv6..."
sudo tee "$CONF_FILE" > /dev/null <<EOF
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
EOF
echo "[*] Applying sysctl changes..."
sudo sysctl --system
echo "[*] IPv6 has been disabled. Current interfaces:"
ip a | grep inet6 || echo "No IPv6 addresses detected"
# COCKPIT CONFIG
sudo systemctl enable --now cockpit.socket
# Create admin user and set password
sudo adduser --disabled-password --gecos "" $ADMINUSER
echo "${ADMINUSER}:${ADMINUSER_PASS}" | sudo chpasswd
sudo usermod -aG sudo $ADMINUSER
# ==== UFW CONFIG ====
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 8080/tcp
sudo ufw allow 443/tcp
sudo ufw allow 3306/tcp
sudo ufw allow 4444/tcp
sudo ufw allow 4567/tcp
sudo ufw allow 4568/tcp
sudo ufw allow 9090/tcp
sudo ufw --force enable
# ==== SHARED STORAGE INIT WITH RETRIES ====
retry_mkdir() {
    local dir=$1
    local attempt=1
    local max_attempts=5
    local interval=3
    until sudo -u www-data mkdir -p "$dir"; do
        echo "Failed to create $dir, retrying ($attempt/$max_attempts)..."
        sleep $interval
        ((attempt++))
        if (( attempt > max_attempts )); then
            echo "ERROR: Could not create $dir after $max_attempts attempts"
            exit 1
        fi
    done
}
echo "www-data perms.."
sudo usermod -aG www-data $USER
echo "Verifying storage.. This may take a while."
retry_mkdir "$OBJECT_STORAGE_PATH"
retry_mkdir "$OBJECT_STORAGE_PATH/backups"
retry_mkdir "$OBJECT_STORAGE_PATH/wordpress"
echo "Storage confirmed."

# ==== WP-CLI INSTALL ====
if ! command -v wp &> /dev/null; then
    wget https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
    chmod +x wp-cli.phar
    sudo mv wp-cli.phar /usr/local/bin/wp
fi
# ==== CLUSTER NODES FILE ====
CLUSTER_NODES_FILE="$OBJECT_STORAGE_PATH/cluster_nodes.json"

# Ensure the directory exists and is group-writable

# Initialize the cluster file if missing
if [[ ! -f "$CLUSTER_NODES_FILE" ]]; then
    sudo -u www-data tee "$CLUSTER_NODES_FILE" > /dev/null <<< '{"hostnames":[]}'
fi

# Function to update cluster nodes file
update_cluster_file() {
    local hostname=$NODE_NAME_CLUSTER
    local attempt=1
    local max_attempts=5
    local interval=2

    while (( attempt <= max_attempts )); do
        # Check if hostname already exists
        if ! jq -e ".hostnames | index(\"$hostname\")" "$CLUSTER_NODES_FILE" >/dev/null; then
            tmpfile=$(mktemp)
            jq ".hostnames += [\"$hostname\"]" "$CLUSTER_NODES_FILE" > "$tmpfile"

            # Write back as www-data to ensure proper permissions
            sudo -u www-data tee "$CLUSTER_NODES_FILE" > /dev/null < "$tmpfile" && break

            echo "Failed to update cluster file, retrying ($attempt/$max_attempts)..."
        else
            break
        fi
        sleep $interval
        ((attempt++))
    done

    if (( attempt > max_attempts )); then
        echo "ERROR: Could not update cluster_nodes.json after $max_attempts attempts"
        exit 1
    fi
}

update_cluster_file "$NODE_HOSTNAME"

# ==== NODE ROLE DETECTION (FIXED) ====
NODE_ROLE="backup"  # default

# Read all hostnames in cluster file
CLUSTER_HOSTS=($(jq -r '.hostnames[]' "$CLUSTER_NODES_FILE"))
ACTIVE_NODES=()
for host in "${CLUSTER_HOSTS[@]}"; do
    [[ "$host" == "$NODE_HOSTNAME" ]] && continue
    HOST_IP=$(dig +short "$host" | head -n1)
    if [[ -n "$HOST_IP" ]]; then
        if nc -z -w2 "$HOST_IP" 3306 2>/dev/null; then
            echo "Detected active Galera node at $host ($HOST_IP)"
            ACTIVE_NODES+=("$HOST_IP")
        fi
    fi
done

# Determine node role
if [[ ${#ACTIVE_NODES[@]} -eq 0 ]]; then
    NODE_ROLE="master"
fi
echo "Detected Node Role: $NODE_ROLE"

# ==== GALERA CLUSTER ADDRESS (DYNAMIC) ====
if [[ "$NODE_ROLE" == "master" ]]; then
    GALERA_CLUSTER_ADDRESS="gcomm://"
else
    GALERA_CLUSTER_ADDRESS="gcomm://$(IFS=,; echo "${ACTIVE_NODES[*]}")"
fi

# ==== WRITE GALERA CONFIG WITH WP-OPTIMIZED TUNINGS ====
sudo tee "$GALERA_CONF_FILE" > /dev/null <<EOF
[mysqld]
bind-address=0.0.0.0
default_storage_engine=InnoDB
innodb_file_per_table=1
innodb_buffer_pool_size=1G
innodb_log_file_size=256M
innodb_flush_log_at_trx_commit=2
innodb_flush_method=O_DIRECT
binlog_format=ROW
wsrep_on=ON
wsrep_provider=/usr/lib/galera/libgalera_smm.so
wsrep_cluster_name="$GALERA_CLUSTER_NAME"
wsrep_cluster_address="$GALERA_CLUSTER_ADDRESS"
wsrep_node_address="$NODE_IP"
wsrep_sst_method=rsync
wsrep_slave_threads=4
wsrep_certify_nonPK=1
max_connections=500
thread_cache_size=50
query_cache_type=0
query_cache_size=0
tmp_table_size=64M
max_heap_table_size=64M
table_open_cache=1024
slow_query_log=1
slow_query_log_file=/var/log/mysql/slow.log
long_query_time=2
EOF
# ==== START GALERA WITH RETRIES ====
start_galera() {
    local attempt=1
    local MAX_RETRIES=12
    local RETRY_INTERVAL=5

    if [[ "$NODE_ROLE" == "master" ]]; then
        echo "Bootstrapping new Galera cluster as MASTER..."
        until sudo galera_new_cluster; do
            echo "Galera bootstrap failed, retrying ($attempt/$MAX_RETRIES)..."
            sleep $RETRY_INTERVAL
            ((attempt++))
            if (( attempt > MAX_RETRIES )); then
                echo "Failed to bootstrap Galera cluster"
                exit 1
            fi
        done
    else
        echo "Joining existing Galera cluster as BACKUP..."
        until sudo systemctl start mariadb; do
            echo "Galera join failed, retrying ($attempt/$MAX_RETRIES)..."
            sleep $RETRY_INTERVAL
            ((attempt++))
            if (( attempt > MAX_RETRIES )); then
                echo "Failed to join Galera cluster"
                exit 1
            fi
        done
    fi
}

echo "Restarting database services..."
sudo systemctl restart mariadb
echo "Simmer down..."
sleep 2

# ==== OPTIONAL: WAIT FOR GALERA READY STATUS ====
echo "Waiting for Galera node to become ready..."
for i in {1..12}; do
    STATUS=$(sudo mysql -u root -N -B -e "SHOW STATUS LIKE 'wsrep_ready';" 2>/dev/null | awk '{print $2}')
    if [[ "$STATUS" == "ON" ]]; then
        echo "Galera node is ready!"
        break
    fi
    echo "Waiting for wsrep_ready=ON... ($i/12)"
    sleep 2
done

echo "MariaDB + Galera startup complete."
echo "FPM.."
# ==== DYNAMIC PHP-FPM SOCKET ====
PHP_SOCK=$(find /run/php/ -name "php*-fpm.sock" | head -n1)
if [[ -z "$PHP_SOCK" ]]; then
    echo "PHP-FPM socket not found!"
    exit 1
fi
echo "NGINX.."

#############################
### PREFLIGHT CHECK COMPLETE!
### DO THE PLATFORM INSTALL!!
#############################


# ==== WORDPRESS NGINX CONFIGURATION ====
sudo rm -f /etc/nginx/sites-enabled/default
sudo tee /etc/nginx/sites-available/wordpress > /dev/null <<EOF
server {
    listen 80;
    server_name $NODE_HOSTNAME;
    root $OBJECT_STORAGE_PATH/wordpress;
    index index.php index.html index.htm;

    location / {
        try_files \$uri \$uri/ /index.php?\$args;
    }

    location ~ \.php\$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:$PHP_SOCK;
        fastcgi_read_timeout 120s;
    }

}
EOF



sudo ln -sf /etc/nginx/sites-available/wordpress /etc/nginx/sites-enabled/
sudo systemctl restart nginx
# ======== Vars ========
REDIS_CONF="/etc/redis/redis.conf"
REDIS_HOST="127.0.0.1"
REDIS_PORT="6379"
REDIS_DB="0"
WP_PATH="$OBJECT_STORAGE_PATH"
WP_FULL_PATH="$WP_PATH/wordpress"



echo "[*] Installing Redis and PHP Redis extension..."

echo "[*] Configuring Redis for local-only and LRU eviction..."
sudo sed -i 's/^# maxmemory <bytes>/maxmemory 256mb/' "$REDIS_CONF"
sudo sed -i 's/^# maxmemory-policy noeviction/maxmemory-policy allkeys-lru/' "$REDIS_CONF"
sudo sed -i 's/^bind .*/bind 127.0.0.1/' "$REDIS_CONF"
sudo sed -i 's/^protected-mode .*/protected-mode yes/' "$REDIS_CONF"
sudo sed -i 's/^supervised .*/supervised systemd/' "$REDIS_CONF"

sudo systemctl enable redis-server --now


echo "WORDPRESS-CHECKS.. [1/2]"

WP_PATH="$OBJECT_STORAGE_PATH"
WP_FULL_PATH="$WP_PATH/wordpress"

# ==== DETECT OR CREATE DB ====
if [ -f "$WP_FULL_PATH/wp-config.php" ]; then
    echo "Existing WordPress detected. Reading database info from wp-config.php..."
    WP_DB_NAME=$(grep "define('DB_NAME'" "$WP_FULL_PATH/wp-config.php" | cut -d "'" -f 4)
    WP_DB_USER=$(grep "define('DB_USER'" "$WP_FULL_PATH/wp-config.php" | cut -d "'" -f 4)
    WP_DB_PASS=$(grep "define('DB_PASSWORD'" "$WP_FULL_PATH/wp-config.php" | cut -d "'" -f 4)
    echo "Using existing DB: $WP_DB_NAME"
else
    echo "No existing WordPress detected. Creating new database..."
    WP_DB_NAME="wp_$(date +%s | sha256sum | head -c6)"
    WP_DB_USER="user_$(date +%s | sha256sum | head -c6)"
    WP_DB_PASS=$(tr -dc 'A-Za-z0-9' </dev/urandom | head -c16)

    sudo mysql -u root <<MYSQL_SCRIPT
CREATE DATABASE IF NOT EXISTS $WP_DB_NAME;
CREATE USER IF NOT EXISTS '$WP_DB_USER'@'%' IDENTIFIED BY '$WP_DB_PASS';
GRANT ALL PRIVILEGES ON $WP_DB_NAME.* TO '$WP_DB_USER'@'%';
FLUSH PRIVILEGES;
MYSQL_SCRIPT

    echo "Created new DB: $WP_DB_NAME"
fi

echo "WORDPRESS-CHECKS.. [2/2]"
# ==== INSTALL WORDPRESS IF NOT ALREADY ====
if [ -f "$WP_FULL_PATH/wp-config.php" ]; then
    echo "WordPress already installed.. Skipping installation."
else
   echo "WordPress not installed. Installing now..."
   if [ "$USE_RANDOM_ADMIN" = true ]; then
       WP_ADMIN_USER="${CUSTOM_ADMIN:-admin}_$(tr -dc 'A-Za-z0-9' </dev/urandom | head -c6)"
   else
       WP_ADMIN_USER="${CUSTOM_ADMIN:-admin}"
   fi

    WP_ADMIN_PASS=$(tr -dc 'A-Za-z0-9' </dev/urandom | head -c16)
    WP_ADMIN_EMAIL="admin@$NODE_HOSTNAME"

    # Download WordPress if not already present

# -----------------------------
# CONFIG
# -----------------------------
TMPDIR="${TMPDIR:-/tmp/wpdeploy}"
WORDPRESS_URL="https://wordpress.org/latest.tar.gz"

# -----------------------------
# FUNCTIONS
# -----------------------------

download_wordpress() {
    mkdir -p "$TMPDIR"
    cd "$TMPDIR"
    echo "[*] Downloading latest WordPress..."
    wget "$WORDPRESS_URL" -O latest.tar.gz
}

check_objectstore() {
    echo "[*] Checking object store: $OBJECT_STORAGE_PATH"
    sudo -u www-data mkdir -p "$OBJECT_STORAGE_PATH/wordpress" || {
        echo "[!] ERROR: Cannot create directory. Check mount or permissions."
        exit 1
    }
    if ! sudo -u www-data touch "$OBJECT_STORAGE_PATH/wordpress/.write_test" &> /dev/null; then
        echo "[!] ERROR: Cannot write to object store. Check mount or permissions."
        exit 1
    fi
     rm -f "$OBJECT_STORAGE_PATH/wordpress/.write_test"
}

deploy_wordpress() {
    echo "[*] Deploying WordPress to object store..."
    cd "$TMPDIR"
    # Extract directly to the mounted object store
    sudo -u www-data tar -vxzf latest.tar.gz -C "$OBJECT_STORAGE_PATH/"
}

cleanup() {
    echo "[*] Cleaning up temporary files..."
    rm -rf "$TMPDIR"
}

# -----------------------------
# MAIN
# -----------------------------
download_wordpress
check_objectstore
deploy_wordpress
cleanup

    # Create config if missing
    if [[ ! -f "$WP_PATH/wp-config.php" ]]; then
        sudo -u www-data wp config create --path="$WP_FULL_PATH" \
            --dbname="$WP_DB_NAME" --dbuser="$WP_DB_USER" --dbpass="$WP_DB_PASS" --dbhost="localhost"
    fi

    # Install WordPress
    echo "Configure Wordpress..."
    sudo -u www-data wp core install --path="$WP_FULL_PATH" \
        --url="http://$WWW_NAME" --title="$WWW_NAME" \
        --admin_user="$WP_ADMIN_USER" --admin_password="$WP_ADMIN_PASS" \
        --admin_email="$WP_ADMIN_EMAIL" --skip-email --path="$WP_FULL_PATH"

# Generate random login slug at the top
RANDOM_SLUG=$(head /dev/urandom | tr -dc a-z0-9 | head -c 10)

echo "[*] Installing and activating plugins (Redis, LSCache, Cloudflare, WPS Hide Login)..."
# Install & activate all plugins in one call

echo "[*] Installing Redis Object Cache plugin for WordPress..."
sudo -u www-data mkdir -p "$WP_FULL_PATH/wp-content/plugins"
cd "$WP_FULL_PATH/wp-content/plugins"
if [[ ! -d "redis-cache" ]]; then
    sudo -u www-data wget https://downloads.wordpress.org/plugin/redis-cache.latest-stable.zip
    sudo -u www-data unzip redis-cache.latest-stable.zip
    sudo -u www-data rm redis-cache.latest-stable.zip
fi

sudo -u www-data wp plugin install cache-enabler litespeed-cache cloudflare wps-hide-login redis-cache --activate --path="$WP_FULL_PATH"

# Enable Redis (plugin-specific post-activation command)
sudo -u www-data wp redis enable --path="$WP_FULL_PATH"

echo "[*] Configuring LiteSpeed Cache options and pre-warming cache..."
sudo -u www-data wp eval '
update_option("ls_db_cache_enabled", 1);
update_option("ls_page_cache_enabled", 1);
update_option("ls_page_cache_lifetime", 1800);
update_option("ls_object_cache_ttl", 300);
update_option("ls_object_cache_type", "redis");
update_option("ls_object_cache_host", "127.0.0.1");
update_option("ls_object_cache_port", 6379);
update_option("ls_object_cache_persistent", 1);
update_option("ls_object_cache_db", 1);
do_action("litespeed_cache_preload");
' --path="$WP_FULL_PATH"

sudo -u www-data wp option update whl_page "$RANDOM_SLUG" --path="$WP_FULL_PATH"

## CLOUDFLARE PLUGIN CONFIG
#sudo -u www-data wp option update cloudflare_email "your-email@example.com" --path="$WP_FULL_PATH"
#sudo -u www-data wp option update cloudflare_api_key "your-global-api-key-or-token" --path="$WP_FULL_PATH"
#sudo -u www-data wp option update cloudflare_domain "yourdomain.com" --path="$WP_FULL_PATH"
# Enable automatic cache purge on content updates
#sudo -u www-data wp option update cloudflare_auto_cache_purge 1 --path="$WP_FULL_PATH"
# Enable development mode toggle (optional)
echo "[*] Deployment complete! WordPress is in $OBJECT_STORAGE_PATH/wordpress"

fi


PLUGIN_DIR="$WP_FULL_PATH/wp-content/plugins/node-probe"
PLUGIN_FILE="$PLUGIN_DIR/node-probe.php"

# Create plugin directory if it doesn't exist
sudo -u www-data mkdir -p "$PLUGIN_DIR"

# Backup existing plugin if it exists
if [ -f "$PLUGIN_FILE" ]; then
    cp "$PLUGIN_FILE" "$PLUGIN_FILE.bak.$(date +%Y%m%d%H%M%S)"
fi

# Write the updated plugin
sudo -u www-data tee "$PLUGIN_FILE" > /dev/null <<'EOF'
<?php
/*
Plugin Name: Node Probe
Description: Shows server hostname at top of pages, or outputs hostname immediately for ?node=1 or curl testing
Version: 2.1
Author: Gabe
*/

// Mode 2: Direct output for ?node=1
add_action('init', function() {
    if (isset($_GET['node'])) {
        // Prevent caching
        header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
        header('Pragma: no-cache');
        header('Expires: 0');

        echo esc_html(gethostname());
        exit;
    }
});

// Mode 3: Direct output for curl / automated tests using special header
add_action('init', function() {
    if (isset($_SERVER['HTTP_X_NODE_TEST'])) {
        header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
        header('Pragma: no-cache');
        header('Expires: 0');

        echo esc_html(gethostname());
        exit;
    }
});

// Mode 1: Normal page load - visible top bar in browser
add_action('template_redirect', function() {
    if (!isset($_GET['node']) && !isset($_SERVER['HTTP_X_NODE_TEST'])) {
        $hostname = esc_html(gethostname());
        echo '<div style="position:fixed; top:0; left:0; width:100%; background:#ff0; color:#000; padding:5px; text-align:center; z-index:9999; font-weight:bold;">Hostname: ' . $hostname . '</div>';
        echo '<style>body { padding-top:30px; }</style>';
        flush(); // Immediately send output to client
    }
});
EOF
sudo -u www-data wp plugin activate node-probe --path="$WP_FULL_PATH"
#  Remove bloat
sudo -u www-data wp plugin delete hello
sudo -u www-data wp theme list --status=inactive --field=name --path="$WP_FULL_PATH" | xargs -r -n1 sudo -u www-data wp theme delete --path="$WP_FULL_PATH"

if [ "$ENABLE_CUSTOM_THEME" = true ]; then
    echo "Installing and activating theme: $THEME_SLUG..."
sudo -u www-data wp theme install "$THEME_SLUG" --activate
else
    echo "Skipping theme installation/activation."
fi
echo "Done."



if [ "$AUTOUPDATE_PLUGINS" = true ]; then
    echo "Updating all plugins and enabling auto-updates..."
sudo -u www-data wp plugin list --field=name | xargs -n1 sudo -u www-data wp plugin auto-updates enable
else
    echo "Skipping plugin updates and auto-update enable."
fi


if [ "$COMMENTS_ENABLED" = true ]; then
    echo "Enabling comments sitewide..."

    # Open comments for all existing posts and pages
    sudo -u www-data wp post list --post_type=post --format=ids | xargs -n1 sudo -u www-data wp post update --comment_status=open
    sudo -u www-data wp post list --post_type=page --format=ids | xargs -n1 sudo -u www-data wp post update --comment_status=open

    # Set default for new content
    sudo -u www-data wp option update default_comment_status open
    sudo -u www-data wp option update default_ping_status open

    echo "Comments enabled sitewide."

else
    echo "Disabling comments sitewide..."

    # Close comments for all existing posts and pages
    sudo -u www-data wp post list --post_type=post --format=ids | xargs -n1 sudo -u www-data wp post update --comment_status=closed
    sudo -u www-data wp post list --post_type=page --format=ids | xargs -n1 sudo -u www-data wp post update --comment_status=closed

    # Set default for new content
    sudo -u www-data wp option update default_comment_status closed
    sudo -u www-data wp option update default_ping_status closed

    echo "Comments disabled sitewide."
fi

if [ "$PERMALINKS" = true ]; then
    sudo -u www-data wp rewrite structure "$PERMALINK_STRUCTURE" --hard --path="$WP_FULL_PATH"
    sudo -u www-data wp rewrite flush --hard --path="$WP_FULL_PATH"
fi

####
####
#### DONE
####
####
####
echo "Done."
cd $HOME




# KeepAliveD -- OFF
sudo systemctl daemon-reload
#sudo systemctl enable keepalived
#sudo systemctl restart keepalived || {
#    echo "Keepalived failed, check network interface and VIP"
#    exit 1
#}


echo "=== Installing MariaDB Galera Phoenix cluster helper ==="
# Create maria-cl.sh 
# Write first part: expand OBJECT_STORAGE_PATH
sudo tee "$SCRIPT_PATH" >/dev/null <<EOF
#!/bin/bash
# maria-cl.sh v3.5
# MariaDB Galera helper with last-man-standing + self-heal + first-node persistence
# Usage: /usr/local/bin/maria-cl.sh [--dry-run] [--lock-ttl <secs>] [--emit-recovery-script]

set -euo pipefail
VER="v3.5"

LOG() { echo "\$(date '+%a %b %d %T %Y') - \$*"; }

# CONFIG
NODE_FILE="$OBJECT_STORAGE_PATH/cluster_nodes.json"
CAND_DIR="$OBJECT_STORAGE_PATH/candidates"
LOCKDIR="$OBJECT_STORAGE_PATH/lastman.lockdir"
NODE="\$(hostname -f)"
GALERA_PORT=4567
RETRY_INTERVAL=5
JOIN_RETRIES=12
JOIN_WAIT=5
MAX_ATTEMPTS=60
MYSQL_DATADIR="/var/lib/mysql"
DEFAULT_LOCK_TTL=1800

# CLI args
DRY_RUN=0
LOCK_TTL="\$DEFAULT_LOCK_TTL"
EMIT_RECOVER=0
EOF

# Write second part: literal script
sudo tee -a "$SCRIPT_PATH" >/dev/null <<'SCRIPT'
while [[ $# -gt 0 ]]; do
    case "$1" in
        --dry-run) DRY_RUN=1; shift ;;
        --lock-ttl) LOCK_TTL="$2"; shift 2 ;;
        --emit-recovery-script) EMIT_RECOVER=1; shift ;;
        --help) echo "Usage: $0 [--dry-run] [--lock-ttl <secs>] [--emit-recovery-script]"; exit 0 ;;
        *) echo "Unknown arg: $1"; exit 1 ;;
    esac
done

# Emit recovery script if requested
if [[ "$EMIT_RECOVER" -eq 1 ]]; then
    cat > /usr/local/bin/maria-recover.sh <<'RECOV'
#!/bin/bash
# maria-recover.sh - helper produced by maria-cl.sh (manual run by admin)
set -euo pipefail
NODE=$(hostname -f)
LOG(){ echo "$(date '+%F %T') - $*"; }
DATADIR="/var/lib/mysql"
BACKUP_DIR="/var/lib/mysql.backup.$(date +%Y%m%d%H%M%S)"
LOG "Stopping MariaDB on this node (we assume it's the source node)"
systemctl stop mariadb || true
LOG "Backing up datadir to $BACKUP_DIR"
mkdir -p "$BACKUP_DIR"
rsync -aH --delete "$DATADIR/" "$BACKUP_DIR/"
LOG "Cleaning Galera runtime files from backup"
rm -f "$BACKUP_DIR/grastate.dat" "$BACKUP_DIR/wsrep_recovery.*" "$BACKUP_DIR/galera.cache" || true
LOG "Start MariaDB on source (so it stays primary for SST)"
systemctl start mariadb
LOG "To reseed a target node, follow the steps outlined in this helper."
chmod +x /usr/local/bin/maria-recover.sh
echo "Recovery helper generated. Run it manually on the last-man node when ready."
exit 0
RECOV
    chmod +x /usr/local/bin/maria-recover.sh
    echo "/usr/local/bin/maria-recover.sh written."
    exit 0
fi

# Helpers
probe() { nc -z -w3 "$1" $GALERA_PORT >/dev/null 2>&1; }

get_local_seqno() {
    local seq=0 out
    if command -v galera_recovery >/dev/null 2>&1; then
        out=$(galera_recovery 2>/dev/null || true)
        if [[ -n "$out" ]]; then
            seq=$(echo "$out" | jq -r '.seqno // 0' 2>/dev/null || echo 0)
            if ! [[ "$seq" =~ ^[0-9]+$ ]]; then
                seq=$(echo "$out" | sed -n 's/.*seqno[^0-9]*\([0-9]\+\).*/\1/p' || echo 0)
            fi
        fi
    elif [[ -f "$MYSQL_DATADIR/grastate.dat" ]]; then
        seq=$(awk '/^seqno:/ {print $2; exit}' "$MYSQL_DATADIR/grastate.dat" 2>/dev/null || echo 0)
    fi
    echo "${seq:-0}"
}

write_candidate() {
    local seq="$1" tmpf="${CAND_DIR}/${NODE}.json.tmp" outf="${CAND_DIR}/${NODE}.json"
    jq -n --arg node "$NODE" --argjson seq "$seq" --arg ts "$(date --iso-8601=seconds)" \
        '{node:$node, seqno:$seq, ts:$ts}' > "$tmpf"
    mv -f "$tmpf" "$outf"
}

lock_owner() { cat "${LOCKDIR}/owner" 2>/dev/null || echo ""; }
lock_ts() { cat "${LOCKDIR}/ts" 2>/dev/null || echo ""; }

acquire_lock() {
    if mkdir "$LOCKDIR" 2>/dev/null; then
        echo "$NODE" > "${LOCKDIR}/owner" || true
        date --iso-8601=seconds > "${LOCKDIR}/ts" || true
        return 0
    fi
    if [[ -d "$LOCKDIR" ]]; then
        ts="$(lock_ts)"
        if [[ -n "$ts" ]]; then
            epoch_then=$(date -d "$ts" +%s 2>/dev/null || echo 0)
            epoch_now=$(date +%s)
            age=$((epoch_now - epoch_then))
            if (( age >= LOCK_TTL )); then
                LOG "Lock is stale (age=${age}s >= ${LOCK_TTL}s). Attempting to steal."
                rm -rf "$LOCKDIR" 2>/dev/null || true
                if mkdir "$LOCKDIR" 2>/dev/null; then
                    echo "$NODE" > "${LOCKDIR}/owner" || true
                    date --iso-8601=seconds > "${LOCKDIR}/ts" || true
                    LOG "Successfully stole lock."
                    return 0
                else return 1
                fi
            fi
        fi
    fi
    return 1
}

release_lock() {
    if [[ -d "$LOCKDIR" ]]; then
        owner="$(lock_owner)"
        if [[ "$owner" == "$NODE" ]]; then
            rm -rf "$LOCKDIR"
            LOG "Released lock"
        else
            LOG "Not lock owner (owner=$owner); not removing"
        fi
    fi
}

# Prepare dirs & sanity
mkdir -p "$CAND_DIR"
if ! command -v jq >/dev/null 2>&1; then LOG "ERROR: jq missing"; exit 1; fi
if [[ ! -f "$NODE_FILE" ]]; then LOG "ERROR: node JSON missing: $NODE_FILE"; exit 1; fi

mapfile -t ALL_NODES < <(jq -r '.hostnames[]' "$NODE_FILE")
PEERS=(); for n in "${ALL_NODES[@]}"; do [[ "$n" != "$NODE" ]] && PEERS+=("$n"); done
LOG "Peers: ${PEERS[*]:-<none>}"

if [[ -d "$MYSQL_DATADIR" ]]; then
    if [[ "$DRY_RUN" -eq 1 ]]; then
        LOG "[dry-run] would chown/chmod $MYSQL_DATADIR"
    else
        chown -R mysql:mysql "$MYSQL_DATADIR" || true
        chmod -R 750 "$MYSQL_DATADIR" || true
    fi
fi

# ==== Preflight: try normal single-node start ====
LOG "Preflight: attempting plain MariaDB start without cluster flags."
if systemctl start mariadb; then
    # wait until MariaDB is actually accepting connections
    for i in {1..10}; do
        if mysqladmin ping &>/dev/null; then
            LOG "MariaDB started successfully as standalone. Entering self-heal idle loop."
            
            LOCAL_SEQ=$(get_local_seqno)
            write_candidate "$LOCAL_SEQ"

            # Enter continuous self-heal loop
            while true; do
                REACHABLE=()
                for p in "${PEERS[@]}"; do
                    if probe "$p"; then REACHABLE+=("$p"); fi
                done

                if (( ${#REACHABLE[@]} > 0 )); then
                    LOG "Detected peer(s) returning: ${REACHABLE[*]}. Attempting cluster join."
                    systemctl stop mariadb || true
                    # Proceed to normal join logic
                    break
                fi
                sleep 60
            done
            break
        fi
        sleep 1
    done

    LOG "Standalone MariaDB ready but did not detect peers immediately. Continuing to cluster logic if necessary."
else
    LOG "Plain MariaDB start failed. Proceeding with cluster logic."
    systemctl stop mariadb || true
fi

# ==== First-node persistence ====
BOOTMARKER="${CAND_DIR}/bootmarker.json"
if [[ -f "$BOOTMARKER" ]]; then
    boot_node=$(jq -r '.boot_node // empty' "$BOOTMARKER" 2>/dev/null || echo "")
    if [[ "$boot_node" == "$NODE" ]]; then
        LOG "Bootmarker detected. Node $NODE already performed first-node bootstrap."
        LOCAL_SEQ=$(get_local_seqno)
        write_candidate "$LOCAL_SEQ"
        LOG "Candidate seqno updated. Entering peer monitoring loop."
        for i in $(seq 1 $MAX_ATTEMPTS); do
            found=0
            for p in "${PEERS[@]}"; do
                if probe "$p"; then found=1; break; fi
            done
            if [[ $found -eq 1 ]]; then
                LOG "Detected peer(s) returning. Peers can join normally."
                exit 0
            fi
            sleep "$RETRY_INTERVAL"
        done
        LOG "No peers returned in monitor window. Leaving node running as first-node."
        exit 0
    fi
fi

# Write candidate immediately
LOCAL_SEQ=$(get_local_seqno)
if [[ "$DRY_RUN" -eq 1 ]]; then
    LOG "[dry-run] would write candidate seq=$LOCAL_SEQ"
else
    write_candidate "$LOCAL_SEQ"
fi

# ===== Main loop =====
attempt=0
while (( attempt < MAX_ATTEMPTS )); do
    attempt=$((attempt+1))
    LOG "Main attempt $attempt/$MAX_ATTEMPTS"

    REACHABLE=()
    for p in "${PEERS[@]}"; do
        if probe "$p"; then REACHABLE+=("$p"); fi
    done
    LOG "Reachable peers: ${REACHABLE[*]:-<none>}"

    if (( ${#REACHABLE[@]} > 0 )); then
        # choose best join target
        best_seq=-1; best_node=""
        shopt -s nullglob
        for f in "$CAND_DIR"/*.json; do
            node_name=$(jq -r '.node // empty' "$f" 2>/dev/null || echo "")
            seqno=$(jq -r '.seqno // 0' "$f" 2>/dev/null || echo 0)
            for r in "${REACHABLE[@]}"; do
                if [[ "$r" == "$node_name" ]] && [[ "$seqno" =~ ^[0-9]+$ ]] && (( seqno > best_seq )); then
                    best_seq=$seqno
                    best_node="$node_name"
                fi
            done
        done
        shopt -u nullglob

        JOIN_TARGET="${best_node:-${REACHABLE[0]}}"
        LOG "Chosen join target: $JOIN_TARGET (seq=$best_seq)"

        joined=0
        for i in $(seq 1 $JOIN_RETRIES); do
            if probe "$JOIN_TARGET"; then
                LOG "Join target $JOIN_TARGET reachable (attempt $i/$JOIN_RETRIES)"
                if [[ "$DRY_RUN" -eq 1 ]]; then
                    LOG "[dry-run] would start mariadb to join $JOIN_TARGET"
                    joined=1; break
                fi
                if systemctl start mariadb; then
                    LOG "MariaDB started (join)"
                    joined=1; break
                else
                    LOG "systemctl start mariadb failed (join attempt $i)"
                fi
            else
                LOG "Join target $JOIN_TARGET not reachable yet (attempt $i/$JOIN_RETRIES)"
            fi
            sleep "$JOIN_WAIT"
        done

        if (( joined == 1 )); then
            LOCAL_SEQ=$(get_local_seqno)
            if [[ "$DRY_RUN" -eq 1 ]]; then
                LOG "[dry-run] would update candidate seq=$LOCAL_SEQ"
            else
                write_candidate "$LOCAL_SEQ"
            fi
            LOG "Started and updated candidate. Exiting."
            exit 0
        else
            LOG "Failed to start/join via $JOIN_TARGET; will retry main loop"
            sleep "$RETRY_INTERVAL"
            continue
        fi
    fi

    # no reachable peers -> attempt last-man lock
    LOG "No reachable peers. Attempting to acquire last-man lock (TTL=${LOCK_TTL}s)."
    if [[ "$DRY_RUN" -eq 1 ]]; then
        LOG "[dry-run] would attempt acquire_lock()"
        simulated_acquire=1
        if [[ $simulated_acquire -eq 1 ]]; then
            LOG "[dry-run] would bootstrap if acquired"
            exit 0
        else
            sleep "$RETRY_INTERVAL"
            continue
        fi
    fi

    if acquire_lock; then
        LOG "Acquired lock; double-check peers didn't come up"
        any_up=0
        for p in "${PEERS[@]}"; do
            if probe "$p"; then any_up=1; break; fi
        done
        if [[ $any_up -eq 1 ]]; then
            LOG "Peer came up after lock; releasing and retrying"
            release_lock
            sleep "$RETRY_INTERVAL"
            continue
        fi

        LOG "Performing bootstrap (last-man)"
        systemctl stop mariadb || true
        rm -f /run/mysqld/wsrep-start-position || true
        systemctl set-environment _WSREP_NEW_CLUSTER=--wsrep-new-cluster
        if systemctl start mariadb; then
            systemctl unset-environment _WSREP_NEW_CLUSTER
            LOG "Bootstrap succeeded on $NODE"

            # Write bootmarker
            jq -n --arg node "$NODE" --arg ts "$(date --iso-8601=seconds)" \
                '{boot_node:$node, ts:$ts}' > "${CAND_DIR}/bootmarker.json.tmp"
            mv -f "${CAND_DIR}/bootmarker.json.tmp" "${CAND_DIR}/bootmarker.json"

            LOCAL_SEQ=$(get_local_seqno)
            write_candidate "$LOCAL_SEQ"
            LOG "First-node bootstrap complete and candidates updated"

            for i in $(seq 1 $MAX_ATTEMPTS); do
                found=0
                for p in "${PEERS[@]}"; do
                    if probe "$p"; then found=1; break; fi
                done
                if [[ $found -eq 1 ]]; then
                    LOG "Detected peer(s) returning; releasing lock and letting them join"
                    release_lock
                    exit 0
                fi
                sleep "$RETRY_INTERVAL"
            done

            LOG "No peers returned in monitor window; leaving bootstrap running and lock held"
            exit 0
        else
            LOG "Bootstrap failed after acquiring lock; cleaning up and retrying later"
            systemctl unset-environment _WSREP_NEW_CLUSTER || true
            release_lock
            sleep "$RETRY_INTERVAL"
            continue
        fi
    else
        owner="$(lock_owner)"
        LOG "Failed to acquire lock; lock owned by: ${owner:-<unknown>}"
        if [[ -n "$owner" ]]; then
            for i in $(seq 1 $JOIN_RETRIES); do
                if probe "$owner"; then
                    LOG "Owner $owner reachable; attempting to start to join"
                    if [[ "$DRY_RUN" -eq 1 ]]; then
                        LOG "[dry-run] would start mariadb to join $owner"
                        exit 0
                    fi
                    if systemctl start mariadb; then
                        LOCAL_SEQ=$(get_local_seqno)
                        write_candidate "$LOCAL_SEQ"
                        LOG "Started and joined owner $owner"
                        exit 0
                    else
                        LOG "Failed to start/join owner (attempt $i)"
                    fi
                fi
                sleep "$JOIN_WAIT"
            done
        fi
        LOG "Owner not joinable yet; retrying main loop"
        sleep "$RETRY_INTERVAL"
    fi
done

LOG "ERROR: Exhausted attempts ($MAX_ATTEMPTS). Manual intervention required."
exit 1
SCRIPT

sudo chmod +x "$SCRIPT_PATH"
echo "Created $SCRIPT_PATH"



sudo tee "$SERVICE_PATH" >/dev/null <<EOFFF
[Unit]
Description=MariaDB Galera Phoenix Self-Healing Daemon
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=$SCRIPT_PATH
Environment=OBJECT_STORAGE_PATH=$OBJECT_STORAGE_PATH
Restart=always
RestartSec=5
User=root
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
EOFFF

sudo systemctl daemon-reload
sudo systemctl enable maria-phoenix.service
sudo systemctl disable mariadb || true
sudo systemctl start maria-phoenix.service
echo "MariaDB Galera Phoenix helper installed and running"

# --- Step 0: Clean old WordPress backup files ---
echo "[*] Cleaning old WordPress backup files from sites-enabled..."
sudo mkdir -p /root/nginx-backups
sudo mv /etc/nginx/sites-enabled/wordpress.bak.* /root/nginx-backups/ 2>/dev/null || true
sudo mv /etc/nginx/sites-available/wordpress.bak.* /root/nginx-backups/ 2>/dev/null || true

# --- Step 0b: Remove default site to avoid conflicts ---
echo "[*] Removing default site to prevent conflicts..."
sudo rm -f /etc/nginx/sites-enabled/default

# --- Step 1: Fix nginx repository and key ---
echo "[*] Fixing nginx signing key and repo..."
sudo apt remove nginx -y
sudo apt autoremove -y
sudo rm -f /etc/apt/trusted.gpg.d/nginx.gpg
sudo rm -f /usr/share/keyrings/nginx.gpg
sudo curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo gpg --dearmor -o /usr/share/keyrings/nginx.gpg
sudo bash -c 'cat > /etc/apt/sources.list.d/nginx.list <<EOFSRC
deb [signed-by=/usr/share/keyrings/nginx.gpg] http://nginx.org/packages/debian trixie nginx
deb-src [signed-by=/usr/share/keyrings/nginx.gpg] http://nginx.org/packages/debian trixie nginx
EOFSRC'

# --- Step 2: Install nginx ---
echo "[*] Installing nginx..."
sudo apt update
sudo apt install -y nginx python3-certbot-nginx

# --- Step 3: Ensure FastCGI cache directory exists ---
sudo mkdir -p /var/cache/nginx/fastcgi
sudo chown -R $WWW_USER:$WWW_USER /var/cache/nginx/fastcgi

# --- Step 4: Detect FQDN ---
FQDN=$(hostname -f)
echo "[*] Detected FQDN: $FQDN"

# --- Step 5: Detect PHP-FPM service dynamically ---
PHP_SERVICE=$(systemctl list-units --type=service | grep -E 'php.*-fpm\.service' | awk '{print $1}' | head -n1)
if [ -z "$PHP_SERVICE" ]; then
    echo "[!] No PHP-FPM service detected. Please install php-fpm first."
    exit 1
fi
echo "[*] Detected PHP-FPM service: $PHP_SERVICE"

# --- Step 6: Start and enable PHP-FPM ---
sudo systemctl enable "$PHP_SERVICE"
sudo systemctl start "$PHP_SERVICE"

# --- Step 7: Detect PHP-FPM socket dynamically ---
PHP_FPM_SOCKET=$(find /run/php -type s -name "*.sock" | head -n1)
if [ -z "$PHP_FPM_SOCKET" ]; then
    echo "[!] Could not find PHP-FPM socket. Aborting."
    exit 1
fi
echo "[*] Detected PHP-FPM socket: $PHP_FPM_SOCKET"

# --- Step 8: Write clean WordPress nginx config ---
WP_CONF="/etc/nginx/sites-available/wordpress"
sudo bash -c "cat > $WP_CONF <<'EOF'
server {
    listen 80;
    server_name $FQDN $WWW_NAME;

    root $OBJECT_STORAGE_PATH/wordpress;
    index index.php index.html index.htm;

    # --- Cache control ---
    set \$skip_cache 0;

    if (\$request_method = 'POST') { set \$skip_cache 1; }
    if (\$request_uri ~* '/wp-admin/|/xmlrpc.php|/wp-login.php') { set \$skip_cache 1; }
    if (\$http_cookie ~* 'wordpress_logged_in_|wp-postpass|woocommerce_items_in_cart') { set \$skip_cache 1; }
    if (\$arg_preview = 'true') { set \$skip_cache 1; }
    if (\$arg_nocache = 'true') { set \$skip_cache 1; }

    location / {
        try_files \$uri \$uri/ /index.php?\$args;
    }

    location ~ \.php\$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:$PHP_FPM_SOCKET;
        fastcgi_read_timeout 120s;

        # --- FastCGI caching ---
        fastcgi_cache WORDPRESS;
        fastcgi_cache_key \"\$scheme\$host\$request_uri\";
        fastcgi_cache_bypass \$skip_cache;
        fastcgi_no_cache \$skip_cache;
        fastcgi_cache_valid 200 301 302 60m;
        fastcgi_cache_use_stale error timeout updating invalid_header http_500 http_503;
        fastcgi_cache_min_uses 1;
        fastcgi_cache_lock on;
        fastcgi_cache_lock_timeout 5s;

        add_header X-FastCGI-Cache \$upstream_cache_status;
    }

    location ~* \.(?:ico|css|js|gif|jpe?g|png|webp|woff2?|ttf|svg)\$ {
        expires 30d;
        add_header Cache-Control 'public';
        try_files \$uri =404;
    }
}
EOF"

# --- Step 9: Symlink to sites-enabled ---
sudo ln -sf /etc/nginx/sites-available/wordpress /etc/nginx/sites-enabled/wordpress

# --- Step 10: Test nginx config ---
sudo nginx -t

# --- Step 11: Disable, enable, restart nginx service ---
sudo systemctl disable nginx
sudo systemctl enable nginx
sudo systemctl restart nginx
NGINX_CONF="/etc/nginx/nginx.conf"
CACHE_DIR="/var/cache/nginx/wordpress"
CACHE_ZONE_NAME="WORDPRESS"
PHP_VERSION="8.4"
PHP_FPM_POOL="/etc/php/$PHP_VERSION/fpm/pool.d/www.conf"
NGINX_USER=$(grep '^user' "$NGINX_CONF" | awk '{print $2}' | tr -d ';')
: ${NGINX_USER:=www-data}  # default for Debian

# --- 1. Ensure fastcgi_cache_path exists ---
if ! grep -q "fastcgi_cache_path.*$CACHE_ZONE_NAME" "$NGINX_CONF"; then
    echo "Adding fastcgi_cache zone '$CACHE_ZONE_NAME'..."
    sudo awk -v zone="fastcgi_cache_path $CACHE_DIR levels=1:2 keys_zone=$CACHE_ZONE_NAME:100m inactive=60m;\nfastcgi_cache_key \"\$scheme\$request_method\$host\$request_uri\";" '
    BEGIN {added=0}
/http\s*\{/ && !added {
    print
    print "    " zone
    added=1
    next
}
{print}
' "$NGINX_CONF" | sudo tee "$NGINX_CONF.tmp" >/dev/null

    sudo cp "$NGINX_CONF" "$NGINX_CONF.bak.$(date +%F-%T)"
    sudo mv "$NGINX_CONF.tmp" "$NGINX_CONF"
    echo "fastcgi_cache zone added."
else
    echo "fastcgi_cache zone '$CACHE_ZONE_NAME' already exists."
fi

# --- 2. Ensure cache directory exists and is writable ---
sudo mkdir -p "$CACHE_DIR"
sudo chown -R "$NGINX_USER:$NGINX_USER" "$CACHE_DIR"
sudo chmod -R 750 "$CACHE_DIR"

# --- 3. Fix PHP-FPM socket permissions ---
sudo sed -i "s|^listen\s*=.*|listen = /run/php/php$PHP_VERSION-fpm.sock|" "$PHP_FPM_POOL"
sudo sed -i "s|^listen.owner\s*=.*|listen.owner = $NGINX_USER|" "$PHP_FPM_POOL" 2>/dev/null || echo "listen.owner = $NGINX_USER" | sudo tee -a "$PHP_FPM_POOL"
sudo sed -i "s|^listen.group\s*=.*|listen.group = $NGINX_USER|" "$PHP_FPM_POOL" 2>/dev/null || echo "listen.group = $NGINX_USER" | sudo tee -a "$PHP_FPM_POOL"
sudo sed -i "s|^listen.mode\s*=.*|listen.mode = 0660|" "$PHP_FPM_POOL" 2>/dev/null || echo "listen.mode = 0660" | sudo tee -a "$PHP_FPM_POOL"

# Restart PHP-FPM
sudo systemctl restart php$PHP_VERSION-fpm

# --- 4. Restart Nginx ---
if sudo nginx -t; then
    echo "nginx.conf valid. Restarting Nginx..."
    sudo systemctl restart nginx
else
    echo "nginx.conf test failed! Check manually."
    exit 1
fi

sudo cp /etc/nginx/sites-available/wordpress /etc/nginx/conf.d/wordpress.conf
sudo systemctl restart nginx

# create /home/user/ssl.sh
tee "$HOME/ssl.sh" >/dev/null <<'SSLSH'
#!/bin/bash
# Safe AIO Nginx SSL Script: Regular + Wildcard
# Usage: ./aio_ssl_safe.sh [--dry-run]
# Dry-run simulates all actions

set -euo pipefail

NGINX_DIR="/etc/nginx/conf.d"
CERT_DIR="/etc/letsencrypt/live"
DRY_RUN="no"
MAX_RETRIES=6
SLEEP_INTERVAL=20

if [[ "${1:-}" == "--dry-run" ]]; then
    DRY_RUN="yes"
fi

# --- Ensure SSL options file exists ---
sudo tee /etc/letsencrypt/options-ssl-nginx.conf >/dev/null <<'SSLN'
ssl_session_cache shared:le_nginx_SSL:10m;
SSLN

# --- Ensure DH param exists ---
if [[ ! -f /etc/letsencrypt/ssl-dhparams.pem ]]; then
    echo "[*] Generating /etc/letsencrypt/ssl-dhparams.pem ..."
    sudo openssl dhparam -out /etc/letsencrypt/ssl-dhparams.pem 2048
fi

echo "[*] Scanning $NGINX_DIR for domains..."
DOMAINS=$(grep -hPo 'server_name\s+\K.*' "$NGINX_DIR"/*.conf | tr -d ';' | tr ' ' '\n' | sort -u)

REGULAR_DOMAINS=()
WILDCARD_DOMAINS=()
for d in $DOMAINS; do
    base=$(echo "$d" | awk -F. '{if (NF>2) {sub("^[^.]+\\.", "", $0)}; print $0}')
    if [[ "$base" == *.* && "$base" != "localhost" && "$base" != "local" ]]; then
        if [[ $d == *.*.* ]]; then
            WILDCARD_DOMAINS+=("$base")
        else
            REGULAR_DOMAINS+=("$base")
        fi
    fi
done

REGULAR_DOMAINS=($(printf "%s\n" "${REGULAR_DOMAINS[@]}" | sort -u))
WILDCARD_DOMAINS=($(printf "%s\n" "${WILDCARD_DOMAINS[@]}" | sort -u))

echo "[*] Regular domains:"
printf " - %s\n" "${REGULAR_DOMAINS[@]}"
echo "[*] Wildcard domains:"
printf " - %s\n" "${WILDCARD_DOMAINS[@]}"

# --- Step 1: Regular SSL ---
for domain in "${REGULAR_DOMAINS[@]}"; do
    if [[ "$DRY_RUN" == "yes" ]]; then
        echo "[DRY RUN] Would issue regular SSL for $domain using --nginx"
        continue
    fi

    if sudo certbot certificates | grep -q "Certificate Name: $domain"; then
        echo "[*] Existing certificate found for $domain — skipping renewal"
    else
        echo "[*] Issuing SSL for $domain using --nginx..."
        sudo certbot --nginx -d "$domain" --agree-tos -m admin@"$domain" --redirect
    fi
done

# --- Step 2: Wildcard SSL via manual TXT ---
for domain in "${WILDCARD_DOMAINS[@]}"; do
    if [[ "$DRY_RUN" == "yes" ]]; then
        echo "[DRY RUN] Would issue wildcard SSL for *.$domain (manual TXT)"
        continue
    fi

    if sudo certbot certificates | grep -q "Certificate Name: $domain"; then
        echo "[*] Existing wildcard certificate found for $domain — skipping renewal"
        continue
    fi

    echo "[*] Issuing wildcard SSL for *.$domain ..."
    sudo certbot certonly \
        --manual \
        --preferred-challenges dns \
        -d "$domain" -d "*.$domain" \
        --agree-tos \
        -m admin@"$domain"

    echo "[*] --- IMPORTANT ---"
    echo "[*] Certbot above shows the TXT record for _acme-challenge.$domain"
    echo "[*] Add that TXT record to your DNS now."

    # Wait + retry for DNS propagation
    for i in $(seq 1 $MAX_RETRIES); do
        echo "[*] Attempt $i/$MAX_RETRIES: Checking TXT propagation..."
        sleep $SLEEP_INTERVAL
        if dig +short TXT _acme-challenge.$domain | grep -q "."; then
            echo "[*] TXT record visible!"
            break
        fi
        echo "[!] TXT record not found yet."
        if [[ $i -eq $MAX_RETRIES ]]; then
            echo "[!] TXT record still missing after retries. Exiting."
            exit 1
        fi
    done

    echo "[*] Press Enter to continue once the TXT record is fully propagated."
    read -r
done

# --- Patch Nginx configs (add listen 443 ssl + SSL directives) ---
for FILE in "$NGINX_DIR"/*.conf; do
    echo "[*] Processing $FILE ..."
    if [[ "$DRY_RUN" == "yes" ]]; then
        echo "[DRY RUN] Would backup $FILE"
        echo "[DRY RUN] Would patch SSL directives, add listen 443 ssl, and create redirect"
        continue
    fi

    sudo cp "$FILE" "$FILE.bak"

    # Add listen 443 ssl if missing
    if ! grep -q "listen 443 ssl;" "$FILE"; then
        sudo sed -i "/server_name/i \    listen 443 ssl;" "$FILE"
    fi

  this_domains=$(grep -hPo 'server_name\s+\K.*' "$FILE" | tr -d ';')
    for d in $this_domains; do
        base=$(echo "$d" | awk -F. '{if (NF>2) {sub("^[^.]+\\.", "", $0)}; print $0}')
        CERT_PATH="$CERT_DIR/$base"

        # Only append SSL block if not present
        if ! grep -q "ssl_certificate $CERT_PATH/fullchain.pem;" "$FILE"; then
            sudo sed -i "/server_name/a \\
    ssl_certificate $CERT_PATH/fullchain.pem;\\
    ssl_certificate_key $CERT_PATH/privkey.pem;\\
    include /etc/letsencrypt/options-ssl-nginx.conf;\\
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;" "$FILE"
        fi
    done

    # Create 80->443 redirect if missing
    REDIRECT_FILE="${FILE%.conf}.redirect.conf"
    if [[ ! -f "$REDIRECT_FILE" ]]; then
        REDIRECT_BLOCK="server {
    listen 80;
    return 301 https://\$host\$request_uri;
}"
        sudo bash -c "echo '$REDIRECT_BLOCK' > '$REDIRECT_FILE'"
    fi
done

# --- Test & reload Nginx ---
if [[ "$DRY_RUN" == "yes" ]]; then
    echo "[DRY RUN] Would run nginx -t and reload nginx"
else
    sudo nginx -t && sudo systemctl reload nginx
fi

echo "[*] Script complete."
if [[ "$DRY_RUN" == "yes" ]]; then
    echo "[*] Dry run complete — simulating all steps."
fi
SSLSH

# ==== SSL Routine ====
if [ "$RUN_SSL" = true ]; then
    sudo chmod +x "$HOME/ssl.sh"
    sudo "$HOME/ssl.sh"
fi

PUBLIC_IP=$(ip route get 1.1.1.1 | awk '{for(i=1;i<=NF;i++){if($i=="src"){print $(i+1)}}}')
# -------------------------------
# ASCII Logo (plain text!)
# -------------------------------
# Load ASCII art into $logo array
readarray -t logo <<'LOGO'
 ,-.----.                       C O D E N A M E
 \    /  \    ,---,                                             ,--,     ,--,
 |   :    \ ,--.' |                                     ,--,    |'. \   / .`|
 |   |  .\ :|  |  :       ,---.                 ,---, ,--.'|    ; \ `\ /' / ;
 .   :  |: |:  :  :      '   ,'\            ,-+-. /  ||  |,     `. \  /  / .'
 |   |   \ ::  |  |,--. /   /   |   ,---.  ,--.'|'   |`--'_      \  \/  / ./
 |   : .   /|  :  '   |.   ; ,. :  /     \|   |  ,"' |,' ,'|      \  \.'  /
 ;   | |`-' |  |   /' :'   | |: : /    /  |   | /  | |'  | |       \  ;  ;
 |   | ;    '  :  | | |'   | .; :.    ' / |   | |  | ||  | :      / \  \  \
 :   ' |    |  |  ' | :|   :    |'   ;   /|   | |  |/ '  : |__   ;  /\  \  \
 :   : :    |  :  :_:,' \   \  / '   |  / |   | |--'  |  | '.'|./__;  \  ;  \
 |   | :    |  | ,'      `----'  |   :    |   |/      ;  :    ;|   : / \  \  ;
 `---'.|    `--''                 \   \  /'---'       |  ,   / ;   |/   \  ' |
   `---`                           `----`              ---`-'  `---'     `--`
LOGO

# Find max line length for proper right alignment
maxlen=0
for line in "${logo[@]}"; do
    (( ${#line} > maxlen )) && maxlen=${#line}
done

# Right-align PASSVER on a new line
logo+=("$(printf '%*s' $maxlen "$PASSVER $AUTHOR")")

# -------------------------------
# Compute maximum line length
# -------------------------------
max_len=0
for line in "${logo[@]}"; do
    (( ${#line} > max_len )) && max_len=${#line}
done



# -------------------------------
# Ultra-fast horizontal gradient (normalized by max_len)
# -------------------------------
gradient_string_fast() {
    local str="$1"
    local r1=$2 g1=$3 b1=$4
    local r2=$5 g2=$6 b2=$7
    local len=${#str}
    local out=""
    local t r g b

    for ((i=0;i<len;i++)); do
        t=$(( i * 1000 / (max_len-1) ))   # use max_len for all lines
        r=$(( r1 + (r2 - r1) * t / 1000 ))
        g=$(( g1 + (g2 - g1) * t / 1000 ))
        b=$(( b1 + (b2 - b1) * t / 1000 ))
        out+=$'\e[38;2;'"$r;$g;$b"'m'"${str:i:1}"
    done

    printf "%b\e[0m\n" "$out"
}

gradient_array_horizontal_fast() {
    local -n arr=$1
    local r1=$2 g1=$3 b1=$4
    local r2=$5 g2=$6 b2=$7

    for line in "${arr[@]}"; do
        gradient_string_fast "$line" $r1 $g1 $b1 $r2 $g2 $b2
    done
}

# -------------------------------
# Plain / reset
# -------------------------------
reset_color() {
    for line in "${logo[@]}"; do
        echo "$line"
    done
}

# -------------------------------
# Reusable: color any string fast
# -------------------------------
color_string_fast() {
    local str="$1"
    local fr=$2 fg=$3 fb=$4
    local br=$5 bg=$6 bb=$7
    local out=""
    local len=${#str}

    for ((i=0;i<len;i++)); do
        if [ -z "$br" ]; then
            out+=$'\e[38;2;'"$fr;$fg;$fb"'m'"${str:i:1}"
        else
            out+=$'\e[38;2;'"$fr;$fg;$fb"'m\e[48;2;'"$br;$bg;$bb"'m'"${str:i:1}"
        fi
    done

    printf "%b\e[0m\n" "$out"
}


# === Helper function for colored fade bar text ===
fade_bar_text_demo() {
    local text="$1"
    local bar_length="${2:-20}"   # default length if not provided
    local tr=$3 tg=$4 tb=$5       # text color (RGB)
    local br=$6 bg=$7 bb=$8       # bar color start (RGB)

    local reset="\e[0m"

    # build fade bar
    local bar=""
    for ((i=0; i<bar_length; i++)); do
        # fade intensity
        local r=$((br + (255 - br) * i / bar_length))
        local g=$((bg + (255 - bg) * i / bar_length))
        local b=$((bb + (255 - bb) * i / bar_length))
        bar+="\e[38;2;${r};${g};${b}m▓"
    done
    echo -e "${bar}\e[38;2;${tr};${tg};${tb}m ${text} ${reset}${bar}"
}
# === Section Divider (dark grey) ===
divider() {
    echo -e "\e[38;2;60;60;60m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\e[0m"
}
# === Decide protocol based on RUN_SSL flag ===
if [[ "$RUN_SSL" == "true" ]]; then
    PROTO="https"
else
    PROTO="http"
fi
# === Fancy Info Display ===
#clear
gradient_array_horizontal_fast logo $R1 $G1 $B1 $R2 $G2 $B2
divider
#fade_bar_text_demo "Node Information" 10 0 255 0 0 100 0
#echo -e "\e[38;2;0;255;0m Node Name       : \e[38;2;255;255;255m$NODE_NAME"
#echo -e "\e[38;2;0;255;0m Node Hostname   : \e[38;2;255;255;255m$NODE_HOSTNAME"
#echo -e "\e[38;2;0;255;0m Node IP         : \e[38;2;255;255;255m$NODE_IP"
#echo -e "\e[38;2;0;255;0m Interface       : \e[38;2;255;255;255m$INTERFACE"
#divider
#fade_bar_text_demo "WordPress Setup" 10 255 255 0 150 50 0
echo -e "\e[38;2;0;200;200m WP URL        : \e[38;2;255;255;255m${PROTO}://$WWW_NAME"
echo -e "\e[38;2;0;200;200m Admin URL     : \e[38;2;255;255;255m${PROTO}://$WWW_NAME/$RANDOM_SLUG"
echo -e "\e[38;2;0;200;200m WP Admin      : \e[38;2;255;255;255m$WP_ADMIN_USER / $WP_ADMIN_PASS"
echo -e "\e[38;2;0;200;200m WP Storage    : \e[38;2;255;255;255m$OBJECT_STORAGE_PATH/wordpress"
if [ "$ENABLE_CUSTOM_THEME" = true ]; then
echo -e "\e[38;2;0;200;200m Custom Theme  : \e[38;2;255;255;255m$THEME_SLUG"
fi
if [ "$COMMENTS_ENABLED" = true ]; then
echo -e "\e[38;2;0;200;200m Comments      : \e[38;2;255;255;255mEnabled"
fi
divider
#fade_bar_text_demo "Cockpit Web UI" 10 255 100 0 200 0 0
echo -e "\e[38;2;255;50;50m Cockpit URL   : \e[38;2;255;255;255m${PROTO}://${PUBLIC_IP}:9090"
echo -e "\e[38;2;255;50;50m Admin User    : \e[38;2;255;255;255m${ADMINUSER}"
echo -e "\e[38;2;255;50;50m Password      : \e[38;2;255;255;255m${ADMINUSER_PASS}"
divider
# Record end time
END_TIME=$(date +%s)
ELAPSED=$((END_TIME - START_TIME))

# Calculate time units
WEEKS=$((ELAPSED / 604800))
DAYS=$(((ELAPSED % 604800) / 86400))
HOURS=$(((ELAPSED % 86400) / 3600))
MINUTES=$(((ELAPSED % 3600) / 60))
SECONDS=$((ELAPSED % 60))

# Build smart output
OUTPUT=""
[ $WEEKS -gt 0 ] && OUTPUT+="${WEEKS}w "
[ $DAYS -gt 0 ] && OUTPUT+="${DAYS}d "
[ $HOURS -gt 0 ] && OUTPUT+="${HOURS}h "
[ $MINUTES -gt 0 ] && OUTPUT+="${MINUTES}m "
OUTPUT+="${SECONDS}s"
echo "Script finished in $OUTPUT"
#color_string_fast "Rebooting..." 255 255 0 200 0 0
#sudo reboot
