#!/bin/bash

# ----------------------------------------------------
#  Command: _do
#  Description: A collection of useful command-line utilities for managing WordPress sites.
#  Author: Austin Ginder
#  License: MIT
# ----------------------------------------------------

# --- Global Variables ---
CAPTAINCORE_DO_VERSION="1.4"
GUM_VERSION="0.14.4"
CWEBP_VERSION="1.5.0"
RCLONE_VERSION="1.69.3"
GIT_VERSION="2.50.0"
GUM_CMD=""
CWEBP_CMD=""
IDENTIFY_CMD=""
WP_CLI_CMD=""
RESTIC_CMD=""
DISEMBARK_CMD=""

# --- Helper Functions ---

# ----------------------------------------------------
#  Intelligently finds or creates a private directory.
#  Sets a global variable CAPTAINCORE_PRIVATE_DIR and echoes the path.
# ----------------------------------------------------
function _get_private_dir() {
    # Return immediately if already found
    if [[ -n "$CAPTAINCORE_PRIVATE_DIR" ]]; then
        echo "$CAPTAINCORE_PRIVATE_DIR"
        return 0
    fi

    local wp_root=""
    local parent_dir=""

    # --- Tier 1: Preferred WP-CLI Method (if in a WP directory) ---
    # Check if wp-cli is set up and if we are in a WP installation.
    if setup_wp_cli && "$WP_CLI_CMD" core is-installed --quiet 2>/dev/null; then
        local wp_config_path
        wp_config_path=$("$WP_CLI_CMD" config path --quiet 2>/dev/null)
        if [ -n "$wp_config_path" ] && [ -f "$wp_config_path" ]; then
            wp_root=$(dirname "$wp_config_path")
            parent_dir=$(dirname "$wp_root")

            # --- WPE Specific Checks ---
            # A. Check for _wpeprivate inside the WP root directory first (most common).
            if [ -d "${wp_root}/_wpeprivate" ]; then
                CAPTAINCORE_PRIVATE_DIR="${wp_root}/_wpeprivate"
                echo "$CAPTAINCORE_PRIVATE_DIR"
                return 0
            fi
            # B. Check for _wpeprivate in the parent directory.
            if [ -d "${parent_dir}/_wpeprivate" ]; then
                CAPTAINCORE_PRIVATE_DIR="${parent_dir}/_wpeprivate"
                echo "$CAPTAINCORE_PRIVATE_DIR"
                return 0
            fi

            # --- Standard Checks (relative to WP root's parent) ---
            # Check for a standard ../private directory
            if [ -d "${parent_dir}/private" ]; then
                CAPTAINCORE_PRIVATE_DIR="${parent_dir}/private"
                echo "$CAPTAINCORE_PRIVATE_DIR"
                return 0
            fi
            # Try to create a ../private directory, suppressing errors
            if mkdir -p "${parent_dir}/private" 2>/dev/null; then
                CAPTAINCORE_PRIVATE_DIR="${parent_dir}/private"
                echo "$CAPTAINCORE_PRIVATE_DIR"
                return 0
            fi
            # Fallback to ../tmp if it exists
            if [ -d "${parent_dir}/tmp" ]; then
                CAPTAINCORE_PRIVATE_DIR="${parent_dir}/tmp"
                echo "$CAPTAINCORE_PRIVATE_DIR"
                return 0
            fi
        fi
    fi

    # --- Tier 2: Manual Fallback (if WP-CLI fails or not in a WP install) ---
    local current_dir
    current_dir=$(pwd)
    # WPE check in current directory
    if [ -d "${current_dir}/_wpeprivate" ]; then
        CAPTAINCORE_PRIVATE_DIR="${current_dir}/_wpeprivate"
        echo "$CAPTAINCORE_PRIVATE_DIR"
        return 0
    fi
    # Relative private check
    if [ -d "../private" ]; then
        CAPTAINCORE_PRIVATE_DIR=$(cd ../private && pwd)
        echo "$CAPTAINCORE_PRIVATE_DIR"
        return 0
    fi
    # Attempt to create relative private, suppressing errors
    if mkdir -p "../private" 2>/dev/null; then
        CAPTAINCORE_PRIVATE_DIR=$(cd ../private && pwd)
        echo "$CAPTAINCORE_PRIVATE_DIR"
        return 0
    fi
    # Relative tmp check
    if [ -d "../tmp" ]; then
        CAPTAINCORE_PRIVATE_DIR=$(cd ../tmp && pwd)
        echo "$CAPTAINCORE_PRIVATE_DIR"
        return 0
    fi

    # --- Tier 3: Last Resort Fallback to Home Directory ---
    # Suppress errors in case $HOME is not writable
    if mkdir -p "$HOME/private" 2>/dev/null; then
        CAPTAINCORE_PRIVATE_DIR="$HOME/private"
        echo "$CAPTAINCORE_PRIVATE_DIR"
        return 0
    fi

    echo "Error: Could not find or create a suitable private, writable directory." >&2
    return 1
}

# ----------------------------------------------------
#  Checks for and installs 'disembark' if not present.
#  Prioritizes standard PATH, then a DISEMBARK_DEV_PATH env var.
# ----------------------------------------------------
function setup_disembark() {
    # Return if already found
    if [[ -n "$DISEMBARK_CMD" ]]; then
        return 0
    fi

    # 1. Check if 'disembark' is in the standard PATH
    if command -v disembark &> /dev/null; then
        echo "   - Found 'disembark' in system PATH." >&2
        DISEMBARK_CMD="disembark"
        return 0
    fi

    # 2. Check for a user-defined development path via environment variable
    if [[ -n "$DISEMBARK_DEV_PATH" && -f "$DISEMBARK_DEV_PATH" && -x "$DISEMBARK_DEV_PATH" ]]; then
        echo "   - Found development version of 'disembark' via DISEMBARK_DEV_PATH." >&2
        DISEMBARK_CMD="$DISEMBARK_DEV_PATH"
        return 0
    fi

    # 3. If not found, attempt to install it system-wide
    echo "  Required tool 'disembark' not found. Attempting to install system-wide..." >&2

    # Check for dependencies needed for the installation
    if ! command -v wget &>/dev/null || ! command -v sudo &>/dev/null; then
        echo "  Error: 'wget' and 'sudo' are required to install disembark." >&2
        return 1
    fi

    local temp_file
    temp_file=$(mktemp)

    echo "   - Downloading disembark.phar..."
    if ! wget -q "https://github.com/DisembarkHost/disembark-cli/raw/main/disembark.phar" -O "$temp_file"; then
        echo "  Error: Failed to download disembark.phar." >&2
        rm -f "$temp_file"
        return 1
    fi

    chmod +x "$temp_file"

    echo "   - Moving to /usr/local/bin/disembark. You may be prompted for your password." >&2
    if ! sudo mv "$temp_file" /usr/local/bin/disembark; then
        echo "  Error: Failed to move disembark.phar to /usr/local/bin/." >&2
        rm -f "$temp_file"
        return 1
    fi

    echo "  'disembark' installed successfully." >&2
    DISEMBARK_CMD="/usr/local/bin/disembark"
    return 0
}

# ----------------------------------------------------
#  Checks for and installs Playwright and its browser dependencies.
#  Sets a global variable PLAYWRIGHT_READY on success.
# ----------------------------------------------------
function setup_playwright() {
    # Return if already checked and ready
    if [[ -n "$PLAYWRIGHT_READY" ]]; then
        return 0
    fi

    # --- Pre-flight Checks ---
    if ! command -v node &>/dev/null; then
        echo "❌ Error: Node.js is required for Playwright." >&2
        return 1
    fi
    if ! command -v npm &>/dev/null; then
        echo "❌ Error: npm is required to install Playwright." >&2
        return 1
    fi

    # --- Check for Browser Executable ---
    # This is a more robust check. require('playwright') can succeed,
    # but executablePath() will fail if browsers aren't installed.
    if node -e "require('playwright').chromium.executablePath()" >/dev/null 2>&1; then
        echo "   - ✅ Playwright and required browsers are already installed."
        PLAYWRIGHT_READY=true
        return 0
    fi

    # --- Installation ---
    echo "   - ⚠️ Playwright or its browsers are missing. Attempting to install now..."
    echo "     This may take a few minutes as it downloads the browser binaries."

    # Step 1: Install the NPM package
    if ! npm install playwright; then
        echo "❌ Error: Failed to install the Playwright npm package." >&2
        echo "   Please try running 'npm install playwright' manually in this directory." >&2
        return 1
    fi

    # Step 2: Install the browser binaries (specifically chromium)
    if ! npx playwright install chromium; then
        echo "❌ Error: Failed to download Playwright's browser binaries." >&2
        echo "   Please try running 'npx playwright install chromium' manually." >&2
        return 1
    fi

    echo "   - ✅ Playwright and its browsers installed successfully."
    PLAYWRIGHT_READY=true
    return 0
}

# ----------------------------------------------------
#  Checks for and installs 'gum' if not present. Sets GUM_CMD on success.
# ----------------------------------------------------
function setup_gum() {
    # Return if already found
    if [[ -n "$GUM_CMD" ]]; then return 0; fi

    # If gum is already in the PATH, we're good to go.
    if command -v gum &> /dev/null; then
        GUM_CMD="gum"
        return 0
    fi

    # Find the private directory for storing tools
    local private_dir
    if ! private_dir=$(_get_private_dir); then
        echo "Error: Cannot find a writable directory to install gum." >&2
        return 1
    fi

    # Find the executable inside the private directory if it's already installed
    local existing_executable
    existing_executable=$(find "$private_dir" -name gum -type f 2>/dev/null | head -n 1)
    if [ -n "$existing_executable" ] && [ -x "$existing_executable" ] && "$existing_executable" --version &> /dev/null; then
        GUM_CMD="$existing_executable"
        return 0
    fi
    
    echo "Required tool 'gum' not found. Installing to '${private_dir}'..." >&2
    local original_dir; original_dir=$(pwd)
    cd "$private_dir" || { echo "Error: Could not enter private directory '${private_dir}'." >&2; return 1; }

    local gum_dir_name="gum_${GUM_VERSION}_Linux_x86_64"
    local gum_tarball="${gum_dir_name}.tar.gz"

    if ! curl -sSL "https://github.com/charmbracelet/gum/releases/download/v${GUM_VERSION}/${gum_tarball}" -o "${gum_tarball}"; then
        echo "Error: Failed to download gum." >&2; cd "$original_dir" > /dev/null 2>&1; return 1;
    fi
    
    # Find the path of the 'gum' binary WITHIN the tarball before extracting
    local gum_path_in_tar
    gum_path_in_tar=$(tar -tf "${gum_tarball}" | grep '/gum$' | head -n 1)

    if [ -z "$gum_path_in_tar" ]; then
        echo "Error: Could not find 'gum' executable within the downloaded tarball." >&2
        rm -f "${gum_tarball}"; cd "$original_dir" > /dev/null 2>&1; return 1;
    fi

    # Now extract the tarball
    if ! tar -xf "${gum_tarball}"; then
        echo "Error: Failed to extract gum from tarball." >&2
        rm -f "${gum_tarball}"; cd "$original_dir" > /dev/null 2>&1; return 1;
    fi
    rm -f "${gum_tarball}"

    # The full path to the executable is the private dir + the path from the tarball
    local gum_executable="${private_dir}/${gum_path_in_tar}"

    if [ -f "$gum_executable" ]; then
        chmod +x "$gum_executable"
    else
        echo "Error: gum executable not found at expected path after extraction: ${gum_executable}" >&2
        cd "$original_dir" > /dev/null 2>&1; return 1;
    fi

    # Final check
    if [ -x "$gum_executable" ] && "$gum_executable" --version &> /dev/null; then
        echo "'gum' installed successfully." >&2
        GUM_CMD="$gum_executable"
    else
        echo "Error: gum installation failed. The binary at ${gum_executable} might not be executable or compatible." >&2
        cd "$original_dir" > /dev/null 2>&1; return 1;
    fi
    
    cd "$original_dir" > /dev/null 2>&1; return 0;
}

# ----------------------------------------------------
#  Checks for and installs 'cwebp' if not present. Sets CWEBP_CMD on success.
# ----------------------------------------------------
function setup_cwebp() {
    # Return if already found
    if [[ -n "$CWEBP_CMD" ]]; then return 0; fi

    if command -v cwebp &> /dev/null; then CWEBP_CMD="cwebp"; return 0; fi

    local private_dir
    if ! private_dir=$(_get_private_dir); then
        echo "Error: Cannot find a writable directory to install cwebp." >&2; return 1;
    fi

    local existing_executable
    existing_executable=$(find "$private_dir" -name cwebp -type f 2>/dev/null | head -n 1)
    if [ -n "$existing_executable" ] && [ -x "$existing_executable" ] && "$existing_executable" -version &> /dev/null; then
        CWEBP_CMD="$existing_executable"; return 0;
    fi
    
    echo "Required tool 'cwebp' not found. Installing to '${private_dir}'..." >&2
    local original_dir; original_dir=$(pwd)
    cd "$private_dir" || { echo "Error: Could not enter private directory '${private_dir}'." >&2; return 1; }

    local cwebp_dir_name="libwebp-${CWEBP_VERSION}-linux-x86-64"
    local cwebp_tarball="${cwebp_dir_name}.tar.gz"

    if ! curl -sSL "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/${cwebp_tarball}" -o "${cwebp_tarball}"; then
        echo "Error: Failed to download cwebp." >&2; cd "$original_dir" > /dev/null 2>&1; return 1;
    fi
    
    local cwebp_path_in_tar
    cwebp_path_in_tar=$(tar -tf "${cwebp_tarball}" | grep '/bin/cwebp$' | head -n 1)
    if [ -z "$cwebp_path_in_tar" ]; then
        echo "Error: Could not find 'cwebp' executable within the downloaded tarball." >&2
        rm -f "${cwebp_tarball}"; cd "$original_dir" > /dev/null 2>&1; return 1;
    fi

    if ! tar -xzf "${cwebp_tarball}"; then
        echo "Error: Failed to extract cwebp." >&2; rm -f "${cwebp_tarball}"; cd "$original_dir" > /dev/null 2>&1; return 1;
    fi
    rm -f "${cwebp_tarball}"

    local cwebp_executable="${private_dir}/${cwebp_path_in_tar}"
    if [ -f "$cwebp_executable" ]; then
        chmod +x "$cwebp_executable";
    else
        echo "Error: cwebp executable not found at expected path: ${cwebp_executable}" >&2; cd "$original_dir" > /dev/null 2>&1; return 1;
    fi

    if [ -x "$cwebp_executable" ] && "$cwebp_executable" -version &> /dev/null; then
        echo "'cwebp' installed successfully." >&2; CWEBP_CMD="$cwebp_executable";
    else
        echo "Error: cwebp installation failed." >&2; cd "$original_dir" > /dev/null 2>&1; return 1;
    fi
    
    cd "$original_dir" > /dev/null 2>&1; return 0;
}

# ----------------------------------------------------
#  Checks for and installs ImageMagick if not present. Sets IDENTIFY_CMD on success.
# ----------------------------------------------------
function setup_imagemagick() {
    # Return if already found
    if [[ -n "$IDENTIFY_CMD" ]]; then
        return 0
    fi

    # If identify is already in the PATH, we're good to go.
    if command -v identify &> /dev/null; then
        IDENTIFY_CMD="identify"
        return 0
    fi

    local private_dir
    if ! private_dir=$(_get_private_dir); then
        # Error message is handled by the helper function
        return 1
    fi

    # Define the path where the extracted binary should be
    local identify_executable="${private_dir}/squashfs-root/usr/bin/identify"
    
    # Check if we have already extracted it
    if [ -f "$identify_executable" ] && "$identify_executable" -version &> /dev/null; then
        IDENTIFY_CMD="$identify_executable"
        return 0
    fi

    # If not found, download and extract the AppImage
    echo "Required tool 'identify' not found. Sideloading via AppImage extraction..." >&2

    local imagemagick_appimage_path="${private_dir}/ImageMagick.AppImage"
    
    # Let's use the 'gcc' version as it's a common compiler toolchain for Linux
    local appimage_url="https://github.com/ImageMagick/ImageMagick/releases/download/7.1.1-47/ImageMagick-82572af-gcc-x86_64.AppImage"
    
    echo "Downloading from ${appimage_url}..." >&2
    if ! wget --quiet "$appimage_url" -O "$imagemagick_appimage_path"; then
        echo "Error: Failed to download the ImageMagick AppImage." >&2
        rm -f "$imagemagick_appimage_path" # Clean up partial download
        return 1
    fi
    
    chmod +x "$imagemagick_appimage_path"

    # --- EXTRACTION STEP ---
    # This is the key change to work around the FUSE error.
    echo "Extracting AppImage..." >&2
    
    # Change into the private directory to contain the extraction
    cd "$private_dir" || { echo "Error: Could not enter private directory." >&2; return 1; }
    
    # Run the extraction. This creates a 'squashfs-root' directory.
    if ! ./ImageMagick.AppImage --appimage-extract >/dev/null; then
        echo "Error: Failed to extract the ImageMagick AppImage." >&2
        # Clean up on failure
        rm -f "ImageMagick.AppImage"
        rm -rf "squashfs-root"
        cd - > /dev/null
        return 1
    fi

    # We don't need the AppImage file anymore after extraction
    rm -f "ImageMagick.AppImage"
    
    # Return to the original directory
    cd - > /dev/null

    # Final check
    if [ -f "$identify_executable" ] && "$identify_executable" -version &> /dev/null; then
        echo "'identify' binary extracted successfully to ${private_dir}/squashfs-root/" >&2
        IDENTIFY_CMD="$identify_executable"
    else
        echo "Error: ImageMagick extraction failed. Could not find the 'identify' executable." >&2
        return 1
    fi
}

# ----------------------------------------------------
#  Checks for and installs 'rclone' if not present. Sets RCLONE_CMD on success.
# ----------------------------------------------------
function setup_rclone() {
    # Return if already found
    if [[ -n "$RCLONE_CMD" ]]; then return 0; fi

    if command -v rclone &> /dev/null; then RCLONE_CMD="rclone"; return 0; fi
    if ! command -v unzip &>/dev/null; then echo "Error: 'unzip' command is required for rclone installation." >&2; return 1; fi

    local private_dir
    if ! private_dir=$(_get_private_dir); then
        echo "Error: Cannot find a writable directory to install rclone." >&2; return 1;
    fi
    
    local existing_executable
    existing_executable=$(find "$private_dir" -name rclone -type f 2>/dev/null | head -n 1)
    if [ -n "$existing_executable" ] && [ -x "$existing_executable" ] && "$existing_executable" --version &> /dev/null; then
        RCLONE_CMD="$existing_executable"; return 0;
    fi

    echo "Required tool 'rclone' not found. Installing to '${private_dir}'..." >&2
    local original_dir; original_dir=$(pwd)
    cd "$private_dir" || { echo "Error: Could not enter private directory '${private_dir}'." >&2; return 1; }

    local rclone_zip="rclone-v${RCLONE_VERSION}-linux-amd64.zip"
    if ! curl -sSL "https://github.com/rclone/rclone/releases/download/v${RCLONE_VERSION}/${rclone_zip}" -o "${rclone_zip}"; then
        echo "Error: Failed to download rclone." >&2; cd "$original_dir" > /dev/null 2>&1; return 1;
    fi
    
    local rclone_path_in_zip
    rclone_path_in_zip=$(unzip -l "${rclone_zip}" | grep '/rclone$' | awk '{print $4}' | head -n 1)
    if [ -z "$rclone_path_in_zip" ]; then
        echo "Error: Could not find 'rclone' executable within the downloaded zip." >&2
        rm -f "${rclone_zip}"; cd "$original_dir" > /dev/null 2>&1; return 1;
    fi

    if ! unzip -q -o "${rclone_zip}"; then
        echo "Error: Failed to extract rclone." >&2; rm -f "${rclone_zip}"; cd "$original_dir" > /dev/null 2>&1; return 1;
    fi
    rm -f "${rclone_zip}"
    
    local rclone_executable="${private_dir}/${rclone_path_in_zip}"
    if [ -f "$rclone_executable" ]; then
        chmod +x "$rclone_executable";
    else
        echo "Error: rclone executable not found at expected path: ${rclone_executable}" >&2; cd "$original_dir" > /dev/null 2>&1; return 1;
    fi
    
    if [ -x "$rclone_executable" ] && "$rclone_executable" --version &> /dev/null; then
        echo "'rclone' installed successfully." >&2; RCLONE_CMD="$rclone_executable";
    else
        echo "Error: rclone installation failed." >&2; cd "$original_dir" > /dev/null 2>&1; return 1;
    fi
    
    cd "$original_dir" > /dev/null 2>&1; return 0;
}

# ----------------------------------------------------
#  Checks for and installs 'restic' if not present.
#  Sets RESTIC_CMD on success.
# ----------------------------------------------------
function setup_restic() {
    #  Return if already found
    if [[ -n "$RESTIC_CMD" ]]; then return 0; fi

    #  If restic is already in the PATH, we're good.
    if command -v restic &> /dev/null; then
        RESTIC_CMD="restic"
        return 0
    fi

    # Check for local installation in private dir
    local restic_executable="$HOME/private/restic"
    if [ -f "$restic_executable" ] && "$restic_executable" version &> /dev/null; then
        RESTIC_CMD="$restic_executable"
        return 0
    fi

    #  If not found, download it
    echo "Required tool 'restic' not found. Installing..." >&2
    if ! command -v bunzip2 &>/dev/null; then echo "Error: 'bunzip2' command is required for installation." >&2; return 1; fi
    mkdir -p "$HOME/private"
    cd "$HOME/private" || { echo "Error: Could not enter ~/private." >&2; return 1; }

    local restic_version="0.18.0"
    local restic_archive="restic_${restic_version}_linux_amd64.bz2"
    if ! curl -sL "https://github.com/restic/restic/releases/download/v${restic_version}/${restic_archive}" -o "${restic_archive}"; then
        echo "Error: Failed to download restic." >&2
        cd - > /dev/null
        return 1
    fi

    # Decompress and extract the binary
    bunzip2 -c "${restic_archive}" > restic_temp && mv restic_temp restic
    rm -f "${restic_archive}"
    chmod +x restic

    #  Final check
    if [ -f "$restic_executable" ] && "$restic_executable" version &> /dev/null; then
        echo "'restic' installed successfully." >&2
        RESTIC_CMD="$restic_executable"
    else
        echo "Error: restic installation failed." >&2
        cd - > /dev/null
        return 1
    fi
    cd - > /dev/null
}

# ----------------------------------------------------
#  Checks for and installs 'git' if not present. Sets GIT_CMD on success.
# ----------------------------------------------------
function setup_git() {
    #  Return if already found
    if [[ -n "$GIT_CMD" ]]; then
        return 0
    fi

    #  If git is already in the PATH, we're good to go.
    if command -v git &> /dev/null; then
        GIT_CMD="git"
        return 0
    fi

    # --- Sideloading Logic ---
    echo "Required tool 'git' not found. Attempting to sideload..." >&2
    
    local private_dir
    if ! private_dir=$(_get_private_dir); then
        return 1
    fi
    
    local git_executable="${private_dir}/git/usr/bin/git"

    # Check if git has already been sideloaded
    if [ -f "$git_executable" ] && "$git_executable" --version &> /dev/null; then
        echo "'git' found in private directory." >&2
        GIT_CMD="$git_executable"
        return 0
    fi

    # Check for wget and dpkg-deb, which are required for sideloading
    if ! command -v wget &> /dev/null || ! command -v dpkg-deb &> /dev/null; then
        echo "❌ Error: 'wget' and 'dpkg-deb' are required to sideload git." >&2
        return 1
    fi

    # Determine OS distribution and version
    if [ -f /etc/os-release ]; then
        . /etc/os-release
    else
        echo "❌ Error: Cannot determine OS distribution. /etc/os-release not found." >&2
        return 1
    fi

    if [[ "$ID" != "ubuntu" ]]; then
        echo "❌ Error: Sideloading git is currently only supported on Ubuntu." >&2
        return 1
    fi

    # Construct the download URL for the git package
    # This example uses a recent stable version. You may need to update the version number periodically.
    local git_version="2.47.1-0ppa1~ubuntu16.04.1"
    local git_deb_url="https://launchpad.net/~git-core/+archive/ubuntu/candidate/+build/29298725/+files/git_${git_version}_amd64.deb"
    local git_deb_file="${private_dir}/git_latest.deb"

    echo "Downloading git from ${git_deb_url}..." >&2
    if ! wget -q -O "$git_deb_file" "$git_deb_url"; then
        echo "❌ Error: Failed to download git .deb package." >&2
        rm -f "$git_deb_file"
        return 1
    fi

    echo "Extracting git package..." >&2
    local extract_dir="${private_dir}/git"
    mkdir -p "$extract_dir"
    if ! dpkg-deb -x "$git_deb_file" "$extract_dir"; then
        echo "❌ Error: Failed to extract git .deb package." >&2
        rm -rf "$extract_dir"
        rm -f "$git_deb_file"
        return 1
    fi

    # Clean up the downloaded .deb file
    rm -f "$git_deb_file"

    # Final check
    if [ -f "$git_executable" ] && "$git_executable" --version &> /dev/null; then
        echo "'git' sideloaded successfully." >&2
        GIT_CMD="$git_executable"
        return 0
    else
        echo "❌ Error: git sideloading failed. The git binary is not available after extraction." >&2
        return 1
    fi
}

# ----------------------------------------------------
#  Checks for and finds the 'wp' command. Sets WP_CLI_CMD on success.
# ----------------------------------------------------
function setup_wp_cli() {
    # Return if already found
    if [[ -n "$WP_CLI_CMD" ]]; then return 0; fi

    # 1. Check if 'wp' is already in the PATH (covers interactive shells)
    if command -v wp &> /dev/null; then
        WP_CLI_CMD="wp"
        return 0
    fi

    # 2. If not in PATH, check common absolute paths for cron environments
    local common_paths=(
        "/usr/local/bin/wp"
        "$HOME/bin/wp"
        "/opt/wp-cli/wp"
    )
    for path in "${common_paths[@]}"; do
        if [ -x "$path" ]; then
            WP_CLI_CMD="$path"
            return 0
        fi
    done

    # 3. If still not found, error out
    echo "❌ Error: 'wp' command not found. Please ensure WP-CLI is installed and in your PATH." >&2
    return 1
}

# ----------------------------------------------------
#  (Helper) Uses PHP to check if a file is a WebP image.
# ----------------------------------------------------
function _is_webp_php() {
    local file_path="$1"
    if [ -z "$file_path" ]; then
        return 1 # Return false if no file path is provided
    fi

    # IMAGETYPE_WEBP has a constant value of 18 in PHP.
    # We will embed the file_path directly into the PHP string.
    local php_code="
    \$file_to_check = '${file_path}';
    if (!file_exists(\$file_to_check)) {
        // Silently exit if file doesn't exist, to avoid warnings.
        exit(1);
    }
    if (function_exists('exif_imagetype')) {
        // The @ suppresses warnings for unsupported file types.
        \$image_type = @exif_imagetype(\$file_to_check);
        if (\$image_type === 18) { // 18 is the constant for IMAGETYPE_WEBP
            exit(0); // Exit with success code (true)
        }
    }
    exit(1); // Exit with failure code (false)
    "
    
    if ! setup_wp_cli; then
      if command -v php &> /dev/null; then
        php -r "\$file_path='${file_path}'; ${php_code}"
        return $?
      fi
      return 1
    fi

    # Execute 'wp eval' with the self-contained code. No extra arguments are needed.
    "$WP_CLI_CMD" eval "$php_code"
    return $?
}

# ----------------------------------------------------
#  (Primary Checker) Checks if a file is WebP, using identify or PHP fallback.
# ----------------------------------------------------
function _is_webp() {
    # Determine which method to use, but only do it once.
    if [[ -z "$IDENTIFY_METHOD" ]]; then
        if command -v identify &> /dev/null; then
            export IDENTIFY_METHOD="identify"
        else
            export IDENTIFY_METHOD="php"
        fi
    fi

    # Execute the chosen method
    if [[ "$IDENTIFY_METHOD" == "identify" ]]; then
        # Return false if the file doesn't exist to prevent errors.
        if [ ! -f "$1" ]; then return 1; fi
        if [[ "$(identify -format "%m" "$1")" == "WEBP" ]]; then
            return 0 # It is a WebP file
        else
            return 1 # It is not a WebP file
        fi
    else # Fallback to PHP
        if _is_webp_php "$1"; then
            return 0 # It is a WebP file
        else
            return 1 # It is not a WebP file
        fi
    fi
}

# ----------------------------------------------------
#  Displays detailed help for a specific command.
# ----------------------------------------------------
function show_command_help() {
    local cmd="$1"
    #  If no command is specified, show the general usage.
    if [ -z "$cmd" ]; then
        show_usage
        return
    fi

    #  Display help text based on the command provided.
    case "$cmd" in
        backup)
            echo "Creates a full backup (files + DB) of a WordPress site."
            echo
            echo "Usage: _do backup <folder> [--quiet]"
            echo
            echo "Flags:"
            echo "  --exclude=<pattern>  A file or folder pattern to exclude, relative to the backup folder."
            echo "                     Can be used multiple times (e.g., --exclude=\"wp-content/uploads/\")."             
            echo "  --quiet    Suppress all informational output and print only the final backup URL."
            ;;
        checkpoint)
            echo "Manages versioned checkpoints of a WordPress installation's manifest."
            echo
            echo "Usage: _do checkpoint <subcommand> [arguments]"
            echo
            echo "Subcommands:"
            echo "  create              Creates a new checkpoint of the current plugin/theme/core manifest."
            echo "  list                Lists available checkpoints from the generated list to inspect."
            echo "  list-generate       Generates a detailed list of all checkpoints for fast viewing."
            echo "  revert [<hash>]     Reverts the site to the specified checkpoint hash."
            echo "  show <hash>         Retrieves the details for a specific checkpoint hash."
            echo "  latest              Gets the hash of the most recent checkpoint."
            ;;
        clean)
            echo "Cleans up unused WordPress components or analyzes disk usage."
            echo
            echo "Usage: _do clean <subcommand>"
            echo
            echo "Subcommands:"
            echo "  plugins   Deletes all inactive plugins."
            echo "  themes    Deletes all inactive themes except for the latest default WordPress theme."
            echo "  disk      Provides an interactive disk usage analysis for the current directory."
            ;;
        cron)
            echo "Manages scheduled tasks (cron jobs) for this script."
            echo
            echo "Usage: _do cron <subcommand> [arguments]"
            echo
            echo "Subcommands:"
            echo "  enable                         Adds a job to the system crontab to run '_do cron run' every 10 minutes."
            echo "  list                           Lists all scheduled commands."
            echo "  run                            Executes any scheduled commands that are due."
            echo "  add \"<cmd>\" \"<time>\" \"<freq>\"  Adds a new command to the schedule."
            echo "  delete <id>                    Deletes a command from the schedule."
            echo
            echo "Arguments for 'add':"
            echo "  <cmd>     (Required) The _do command to run, in quotes (e.g., \"update all\")."
            echo "  <time>    (Required) The next run time, in quotes (e.g., \"4am\", \"tomorrow 2pm\", \"+2 hours\")."
            echo "  <freq>    (Required) The frequency, in quotes (e.g., \"1 day\", \"1 week\", \"12 hours\")."
            echo
            echo "Example:"
            echo "  _do cron add \"update all\" \"4am\" \"1 day\""
            ;;
        db)
            echo "Performs various database operations."
            echo
            echo "Usage: _do db <subcommand>"
            echo
            echo "Subcommands:"
            echo "  backup           Performs a DB-only backup to a secure private directory."
            echo "  check-autoload   Checks the size and top 25 largest autoloaded options in the DB."
            echo "  optimize         Converts tables to InnoDB, reports large tables, and cleans transients."
            echo "  change-prefix    Changes the database table prefix."
            ;;
        disembark)
            echo "Remotely installs the Disembark plugin, connects, and initiates a backup."
            echo
            echo "Usage: _do disembark <url> [--debug]"
            echo
            echo "Arguments:"
            echo "  <url>  (Required) The full URL to the WordPress site."
            echo
            echo "Flags:"
            echo "  --debug  Runs the browser automation in headed mode (not headless) for debugging."
            echo
            echo "You will be interactively prompted for an administrator username and password."
            ;;
        dump)
            echo "Dumps the content of files matching a pattern into a single text file."
            echo
            echo "Usage: _do dump \"<pattern>\" [-x <exclude_pattern_1>] [-x <exclude_pattern_2>]..."
            echo
            echo "Arguments:"
            echo "  <pattern>   (Required) The path and file pattern to search for, enclosed in quotes."
            echo
            echo "Flags:"
            echo "  -x <pattern>  (Optional) A file or directory pattern to exclude. Can be used multiple times."
            echo "                To exclude a directory, the pattern MUST end with a forward slash (e.g., 'my-dir/')."
            echo
            echo "Examples:"
            echo "  _do dump \"wp-content/plugins/my-plugin/**/*.php\""
            echo "  _do dump \"*\" -x \"*.log\" -x \"node_modules/\""
            ;;
        email)
            echo "Sends an email using wp_mail via WP-CLI."
            echo
            echo "Usage: _do email"
            echo
            echo "This command will interactively prompt for the recipient, subject, and content."
            ;;
        find)
            echo "Finds files or WordPress components based on specific criteria."
            echo
            echo "Usage: _do find <subcommand> [arguments]"
            echo
            echo "Subcommands:"
            echo "  recent-files [days]  Finds files modified within the last <days>. Defaults to 1 day."
            echo "  slow-plugins [path]  Identifies plugins slowing down WP-CLI. Optionally check a specific page path (e.g., \"/contact\")."
            echo "  hidden-plugins       Detects active plugins that may be hidden from the standard list."
            echo "  malware              Scans for malware and verifies core/plugin file integrity."
            echo "  php-tags [dir]       Finds outdated PHP short tags ('<?'). Defaults to 'wp-content/'."
            ;;
        https)
            echo "Applies HTTPS to all site URLs."
            echo
            echo "Usage: _do https"
            echo
            echo "This command will interactively ask whether to use 'www.' or not in the final URL"
            echo "and then perform a search-and-replace across the entire database."
            ;;
        convert-to-webp)
            echo "Finds and converts large images (JPG, PNG) to WebP format."
            echo
            echo "Usage: _do convert-to-webp [folder] [--all]"
            echo
            echo "Arguments:"
            echo "  [folder] (Optional) The folder to convert. Defaults to 'wp-content/uploads'."
            echo
            echo "Flags:"
            echo "  --all    Convert all images, regardless of size. Defaults to images > 1MB."
            ;;
         install)
            echo "Installs helper or premium plugins."
            echo
            echo "Usage: _do install <subcommand> [--flags]"
            echo
            echo "Subcommands:"
            echo "  kinsta-mu            Installs the Kinsta MU plugin. Use --force to install outside a Kinsta environment."
            echo "  helper               Installs the CaptainCore Helper plugin."
            echo "  events-calendar-pro  Installs The Events Calendar and its Pro version after prompting for a license."
            ;;
        launch)
            echo "Launches a site: updates URL from dev to live, enables search engines, and clears cache."
            echo
            echo "Usage: _do launch [--domain=<domain>]"
            echo
            echo "Flags:"
            echo "  --domain=<domain>  (Optional) The new domain name. If omitted, you will be prompted interactively."
            ;;
        migrate)
            echo "Migrates a site from a backup snapshot."
            echo
            echo "Usage: _do migrate --url=<backup-url> [--update-urls]"
            echo
            echo "  --update-urls   Update urls to destination WordPress site. Default will keep source urls."
            ;;
        monitor)
            echo "Monitors server access logs or errors in real-time."
            echo
            echo "Usage: _do monitor <subcommand> [--flags]"
            echo
            echo "Subcommands:"
            echo "  traffic       Analyzes and monitors top hits from access logs." 
            echo "  errors        Monitors logs for HTTP 500 and PHP fatal errors." 
            echo "  access.log    Provides a real-time stream of the access log."
            echo "  error.log     Provides a real-time stream of the error log."
            echo
            echo "Flags for 'traffic':"
            echo "  --top=<number>   The number of top IP/Status combinations to show. Default is 25." 
            echo "  --now            Start processing from the end of the log file instead of the beginning." 
            ;;
        php-tags)
            echo "Finds outdated or invalid PHP opening tags in PHP files."
            echo
            echo "Usage: _do php-tags [directory]"
            echo
            echo "Arguments:"
            echo "  [directory]  (Optional) The directory to search in. Defaults to 'wp-content/'."
            ;;
        reset)
            echo "Resets WordPress components or permissions."
            echo
            echo "Usage: _do reset <subcommand> [arguments]"
            echo
            echo "Subcommands:"
            echo "  wp           Resets the WordPress installation to a default state."
            echo "  permissions  Resets file and folder permissions to defaults (755 for dirs, 644 for files)."
            ;;
        suspend)
            echo "Activates or deactivates a suspend message shown to visitors."
            echo
            echo "Usage: _do suspend <subcommand> [flags]"
            echo
            echo "Subcommands:"
            echo "  activate      Activates the suspend message. Requires --name and --link flags."
            echo "  deactivate    Deactivates the suspend message."
            echo
            echo "Flags for 'activate':"
            echo "  --name=<business-name>      (Required) The name of the business to display."
            echo "  --link=<business-link>      (Required) The contact link for the business."
            echo "  --wp-content=<path>         (Optional) Path to wp-content directory. Defaults to 'wp-content'."
            echo
            echo "Flags for 'deactivate':"
            echo "  --wp-content=<path>         (Optional) Path to wp-content directory. Defaults to 'wp-content'."
            ;;
        update)
            echo "Handles WordPress core, theme, and plugin updates."
            echo
            echo "Usage: _do update <subcommand>"
            echo
            echo "Subcommands:"
            echo "  all                 Creates a 'before' checkpoint, runs all updates, creates an"
            echo "                      'after' checkpoint, and logs the changes."
            echo "  list                Shows a list of past updates to inspect from the generated list."
            echo "  list-generate       Generates a detailed list of all updates for fast viewing."
            ;;
        upgrade)
            echo "Upgrades the _do script to the latest version."
            echo
            echo "Usage: _do upgrade"
            ;;
        vault)
            echo "Manages secure, full site snapshots in a remote Restic repository."
            echo
            echo "Usage: _do vault <subcommand> [arguments]"
            echo
            echo "Subcommands:"
            echo "  create                Creates a new snapshot of the current site."
            echo "  snapshots [--output]  Lists available snapshots. Use --output for a non-interactive list."
            echo "  snapshot-info <id>    Displays detailed information for a single snapshot."
            echo "  delete <id>           Deletes a specific snapshot by its ID."
            echo "  mount                 Mounts the entire repository to a local folder for Browse."
            echo "  info                  Displays statistics about the repository."
            echo "  prune                 Removes unnecessary data from the repository."
            echo
            echo "Authentication:"
            echo "  This command requires B2 and Restic credentials, provided either by"
            echo "  environment variables (B2_ACCOUNT_ID, B2_ACCOUNT_KEY, RESTIC_PASSWORD,"
            echo "  B2_BUCKET, B2_PATH) or by piping a 5-line secrets file via stdin."
            echo
            echo "Example (stdin):"
            echo "  cat secrets.txt | _do vault snapshots"
            ;;
        version)
            echo "Displays the current version of the _do script."
            echo
            echo "Usage: _do version"
            ;;
        wpcli)
            echo "Checks for and identifies sources of WP-CLI warnings."
            echo
            echo "Usage: _do wpcli <subcommand>"
            echo
            echo "Subcommands:"
            echo "  check     Runs a check to find themes or plugins causing WP-CLI warnings."
            ;;
        zip)
            echo "Creates a zip archive of a specified folder."
            echo
            echo "Usage: _do zip \"<folder>\""
            echo
            echo "Arguments:"
            echo "  <folder>  (Required) The folder to be archived."
            echo
            echo "If the folder is a WordPress installation, a public URL to the zip file will be provided."
            echo "Otherwise, the local file path and size will be displayed."
            ;;
        *)
            echo "Error: Unknown command '$cmd' for help." >&2
            echo ""
            show_usage
            exit 1
            ;;
    esac
}

# ----------------------------------------------------
#  Displays the main help and usage information.
# ----------------------------------------------------
function show_usage() {
    echo "CaptainCore _do (v$CAPTAINCORE_DO_VERSION)"
    echo "--------------------------"
    echo "A collection of useful command-line utilities for managing WordPress sites."
    echo ""
    echo "Usage:"
    echo "  _do <command> [arguments] [--flags]"
    echo ""
    echo "Available Commands:"
    echo "  backup              Creates a full backup (files + DB) of a WordPress site."
    echo "  checkpoint          Manages versioned checkpoints of the site's manifest."
    echo "  clean               Removes unused items like inactive themes or analyzes disk usage."
    echo "  convert-to-webp     Finds and converts large images (JPG, PNG) to WebP format."
    echo "  cron                Manages cron jobs and schedules tasks to run at specific times."
    echo "  db                  Performs various database operations (backup, check-autoload, optimize)."
    echo "  disembark           Remotely connects to a site to generate a backup."
    echo "  dump                Dumps the content of files matching a pattern into a single text file."
    echo "  email               Sends an email using wp_mail via WP-CLI."
    echo "  find                Finds files, slow plugins, hidden plugins or outdated PHP tags."
    echo "  https               Applies HTTPS to all site URLs, with an option for www/non-www."
    echo "  install             Installs helper plugins or premium plugins."
    echo "  launch              Launches a site to a new domain, using a flag or interactively."
    echo "  migrate             Migrates a site from a backup URL or local file."
    echo "  monitor             Monitors server logs or errors in real-time."
    echo "  reset               Resets WordPress components or permissions."
    echo "  suspend             Activates or deactivates a suspend message shown to visitors."
    echo "  update              Runs WordPress updates and logs the changes."
    echo "  upgrade             Upgrades this script to the latest version."
    echo "  vault               Manages secure snapshots in a remote Restic repository."
    echo "  version             Displays the current version of the _do script."
    echo "  wpcli               Checks for and identifies sources of WP-CLI warnings."
    echo "  zip                 Creates a zip archive of a specified folder."
    echo ""
    echo "Run '_do help <command>' for more information on a specific command."
}

# --- Main Entry Point and Argument Parser ---

function main() {
    #  If no arguments are provided, show usage and exit.
    if [ $# -eq 0 ]; then
        show_usage
        exit 0
    fi

    # --- Help Flag Handling ---
    #  Detect 'help <command>' pattern
    if [[ "$1" == "help" ]]; then
        show_command_help "$2"
        exit 0
    fi

    #  Detect '<command> --help' pattern
    for arg in "$@"; do
        if [[ "$arg" == "--help" || "$arg" == "-h" ]]; then
            #  The first non-flag argument is the command we need help for.
            local help_for_cmd=""
            for inner_arg in "$@"; do
                #  Find the first argument that doesn't start with a hyphen.
                if [[ ! "$inner_arg" =~ ^- ]]; then
                    help_for_cmd="$inner_arg"
                    break
                fi
            done
            show_command_help "$help_for_cmd"
            exit 0
        fi
    done

    # --- Centralized Argument Parser ---
    #  This loop separates flags from commands.
    local url_flag=""
    local top_flag=""
    local name_flag=""
    local link_flag=""
    local wp_content_flag=""
    local update_urls_flag=""
    local now_flag=""
    local admin_user_flag=""
    local path_flag=""
    local all_files_flag=""
    local force_flag=""
    local format_flag=""
    local domain_flag=""
    local output_flag=""
    local exclude_patterns=()
    local backup_exclude_patterns=()
    local positional_args=()
    local quiet_flag=""
    local debug_flag=""
    
    while [[ $# -gt 0 ]]; do
      case $1 in
        --url=*)
          url_flag="${1#*=}"
          shift
          ;;
        --domain=*)
          domain_flag="${1#*=}"
          shift
          ;;
        --top=*)
          top_flag="${1#*=}"
          shift
          ;;
        --now)
          now_flag=true
          shift
          ;;
        --name=*)
          name_flag="${1#*=}"
          shift
          ;;
        --link=*)
          link_flag="${1#*=}"
          shift
          ;;
        --wp-content=*)
          wp_content_flag="${1#*=}"
          shift
          ;;
        --update-urls)
          update_urls_flag=true
          shift
          ;;
        --admin_user=*)
          admin_user_flag="${1#*=}"
          shift
          ;;
        --all)
          all_files_flag=true
          shift
          ;;
        --force)
          force_flag=true
          shift
          ;;
        --format=*)
          format_flag="${1#*=}"
          shift
          ;;
        --output)
          output_flag=true
          shift
          ;;
        --path=*)
          path_flag="${1#*=}"
          shift
          ;;
        -x) # Exclude flag
          if [[ -n "$2" ]]; then
            exclude_patterns+=("$2")
            shift 2 # past flag and value
          else
            echo "Error: -x flag requires an argument." >&2
            exit 1
          fi
          ;;
        --exclude=*)
          backup_exclude_patterns+=("${1#*=}")
          shift
          ;;
        --quiet)
          quiet_flag=true
          shift
          ;;
        --debug)
          debug_flag=true
          shift
          ;;
        -*)
          #  This will catch unknown flags like --foo
          echo "Error: Unknown flag: $1" >&2
          show_usage
          exit 1
          ;;
        *)
          #  It's a command or a positional argument
          positional_args+=("$1")
          shift #  past argument
          ;;
      esac
    done

    # --- Global Path Handling ---
    # If a path is provided, change to that directory first.
    # This allows commands to be run from anywhere for a specific site.
    if [[ -n "$path_flag" ]]; then
        if [ -d "$path_flag" ]; then
            cd "$path_flag" || { echo "❌ Error: Could not change directory to '$path_flag'." >&2; exit 1; }
        else
            echo "❌ Error: Provided path '$path_flag' does not exist." >&2
            exit 1
        fi
    fi

    #  The first positional argument is the main command.
    local command="${positional_args[0]}"

    # --- Command Router ---
    #  This routes to the correct function based on the parsed command.
    case "$command" in
        backup)
            full_backup "${positional_args[1]}" "$quiet_flag" "$format_flag" "${backup_exclude_patterns[@]}"
            ;;
        checkpoint)
            local subcommand="${positional_args[1]}"
            case "$subcommand" in
                create)
                    checkpoint_create
                    ;;
                list)
                    checkpoint_list
                    ;;
                list-generate)
                    checkpoint_list_generate
                    ;;
                revert)
                    local hash="${positional_args[2]}"
                    checkpoint_revert "$hash"
                    ;;
                show)
                    local hash="${positional_args[2]}"
                    checkpoint_show "$hash"
                    ;;
                latest)
                    checkpoint_latest
                    ;;
                *)
                    show_command_help "checkpoint"
                    exit 0
                    ;;
            esac
            ;;
        clean)
            local arg1="${positional_args[1]}"
            case "$arg1" in
                plugins)
                    clean_plugins
                    ;;
                themes)
                    clean_themes
                    ;;
                disk)
                    clean_disk
                    ;;
                *)
                    show_command_help "clean"
                    exit 0
                    ;;
            esac
            ;;
        cron)
            local subcommand="${positional_args[1]}"
            case "$subcommand" in
                enable)
                    cron_enable
                    ;;
                list)
                    cron_list
                    ;;
                run)
                    cron_run
                    ;;
                add)
                    cron_add "${positional_args[2]}" "${positional_args[3]}" "${positional_args[4]}"
                    ;;
                delete)
                    cron_delete "${positional_args[2]}"
                    ;;
                *)
                    show_command_help "cron"
                    exit 0
                    ;;
            esac
            ;;
        convert-to-webp)
            # Pass the optional folder (positional_args[1]) and the --all flag
            convert_to_webp "${positional_args[1]}" "$all_files_flag"
            ;;
        db)
            local arg1="${positional_args[1]}"
            case "$arg1" in
                backup)
                    db_backup # Originally from backup-db command 
                    ;;
                check-autoload)
                    db_check_autoload # Originally from db-check-autoload command 
                    ;;
                optimize)
                    db_optimize # Originally from db-optimize command 
                    ;;
                change-prefix)
                    db_change_prefix
                    ;;
                *)
                    show_command_help "db"
                    exit 0
                    ;;
            esac
            ;;
        disembark)
            run_disembark "${positional_args[1]}" "$debug_flag"
            ;;
        dump)
            # There should be exactly 2 positional args total: 'dump' and the pattern.
            if [ ${#positional_args[@]} -ne 2 ]; then
                echo -e "Error: Incorrect number of arguments for 'dump'. It's likely your pattern was expanded by the shell." >&2
                echo "Please wrap the input pattern in double quotes." >&2
                echo -e "\n  Usage: _do dump \"<pattern>\" [-x <exclude1>...]" >&2
                return 1
            fi
            run_dump "${positional_args[1]}" "${exclude_patterns[@]}"
            ;;
        email)
            run_email
            ;;
        find)
            local subcommand="${positional_args[1]}"
            case "$subcommand" in
                recent-files)
                    find_recent_files "${positional_args[2]}"
                    ;;
                slow-plugins)
                    find_slow_plugins "${positional_args[2]}"
                    ;;
                hidden-plugins)
                    find_hidden_plugins
                    ;;
                malware)
                    find_malware
                    ;;
                php-tags)
                    find_outdated_php_tags "${positional_args[2]}"
                    ;;
                *)
                    show_command_help "find"
                    exit 0
                    ;;
            esac
            ;;
        https)
            run_https
            ;;
        install)
            local subcommand="${positional_args[1]}"
            case "$subcommand" in
                kinsta-mu)
                    install_kinsta_mu "$force_flag"
                    ;;
                helper)
                    install_helper
                    ;;
                events-calendar-pro)
                    install_events_calendar_pro
                    ;;
                *)
                    show_command_help "install"
                    exit 0
                    ;;
            esac
            ;;
        launch)
            run_launch "$domain_flag"
            ;;
        migrate)
            if [[ -z "$url_flag" ]]; then
                echo "Error: The 'migrate' command requires the --url=<...> flag." >&2
                show_command_help "migrate"
                exit 1
            fi
            migrate_site "$url_flag" "$update_urls_flag"
            ;;
        monitor)
            local arg1="${positional_args[1]}"
            case "$arg1" in
                traffic)
                    monitor_traffic "$top_flag" "$now_flag"
                    ;;
                errors)
                    monitor_errors
                    ;;
                access.log)
                    monitor_access_log
                    ;;
                error.log)
                    monitor_error_log
                    ;;
                *)
                    show_command_help "monitor"
                    exit 0
                    ;;
            esac
            ;;
        php-tags)
            find_outdated_php_tags "${positional_args[1]}"
            ;;
        reset)
            local subcommand="${positional_args[1]}"
            case "$subcommand" in
                wp)
                    reset_wp "$admin_user_flag"
                    ;;
                permissions)
                    reset_permissions
                    ;;
                *)
                    show_command_help "reset"
                    exit 0
                    ;;
            esac
            ;;
        suspend)
            local arg1="${positional_args[1]}" 
            case "$arg1" in
                activate)
                    suspend_activate "$name_flag" "$link_flag" "$wp_content_flag"
                    ;;
                deactivate)
                    suspend_deactivate "$wp_content_flag"
                    ;;
                *)
                    show_command_help "suspend"
                    exit 0
                    ;;
            esac
            ;;
        update)
            local subcommand="${positional_args[1]}"
            case "$subcommand" in
                all)
                    run_update_all
                    ;;
                list)
                    update_list
                    ;;
                list-generate)
                    update_list_generate
                    ;;
                *)
                    show_command_help "update"
                    exit 1
                    ;;
            esac
            ;;
        upgrade)
            run_upgrade
            ;;
        vault)
            local subcommand="${positional_args[1]}" # Default to snapshots
            case "$subcommand" in
                create)
                    vault_create
                    ;;
                delete)
                    local snapshot_id_to_delete="${positional_args[2]}"
                    vault_delete "$snapshot_id_to_delete"
                    ;;
                snapshot-info)
                    local snapshot_id_to_show="${positional_args[2]}"
                    vault_snapshot_info "$snapshot_id_to_show"
                    ;;
                snapshots)
                    vault_snapshots "$output_flag"
                    ;;
                mount)
                    vault_mount
                    ;;
                info)
                    vault_info
                    ;;
                prune)
                    vault_prune
                    ;;
                *)
                    show_command_help "vault" >&2
                    exit 0
                    ;;
            esac
            ;;
        version|--version|-v)
            show_version
            ;;
        wpcli)
            local subcommand="${positional_args[1]}"
            case "$subcommand" in
                check)
                    wpcli_check
                    ;;
                *)
                    show_command_help "wpcli"
                    exit 0
                    ;;
            esac
            ;;
        zip)
            run_zip "${positional_args[1]}"
            ;;
        *)
            echo "Error: Unknown command '$command'." >&2
            show_usage
            exit 1
            ;;
    esac
}

#  Pass all script arguments to the main function.

# --- Sourced Command Functions ---
# The following functions are sourced from the 'commands/' directory.

# ----------------------------------------------------
#  Creates a full backup of a WordPress site (files + database).
# ----------------------------------------------------
function full_backup() {
    # --- 1. Argument Parsing ---
    local target_folder="$1"
    local quiet_flag="$2"
    local format_flag="$3"
    shift 3  # Move past the first two arguments
    local exclude_patterns=("$@") # The rest of the arguments are the exclude patterns

    # --- 2. Validation ---
    if [ -z "$target_folder" ]
    then echo "Error: Please provide a folder path." >&2; echo "Usage: _do backup <folder>" >&2; return 1;
    fi
    if ! command -v realpath &> /dev/null; then echo "Error: 'realpath' command not found. Please install it." >&2; return 1; fi
    if [ ! -d "$target_folder" ]; then echo "Error: Folder '$target_folder' not found." >&2; return 1; fi

    # --- 3. Setup Paths and Filenames ---
    #  Resolve the absolute path to handle cases like "."
    local full_target_path; full_target_path=$(realpath "$target_folder")
    local parent_dir; parent_dir=$(dirname "$full_target_path")
    local site_dir_name; site_dir_name=$(basename "$full_target_path")

    local today; today=$(date +"%Y-%m-%d")
    local random; random=$(openssl rand -hex 4 | head -c 7)
    local backup_filename="${today}_${random}.zip"
    local original_dir; original_dir=$(pwd)

    #  Change to the parent directory for consistent relative paths in the zip
    cd "$parent_dir" || return 1

    # --- 4. Database Export ---
    if ! setup_wp_cli; then echo "Error: wp-cli is not installed." >&2; cd "$original_dir"; return 1; fi
    local home_url; home_url=$("$WP_CLI_CMD" option get home --path="$site_dir_name" --skip-plugins --skip-themes)
    local name; name=$("$WP_CLI_CMD" option get blogname --path="$site_dir_name" --skip-plugins --skip-themes)
    local database_file="db_export.sql"

    if [[ "$quiet_flag" != "true" ]]; then
        echo "Exporting database for '$name'...";
    fi
    if ! "$WP_CLI_CMD" db export "$site_dir_name/$database_file" --path="$site_dir_name" --add-drop-table --default-character-set=utf8mb4 > /dev/null; then
        echo "Error: Database export failed." >&2
        cd "$original_dir"
        return 1
    fi
    if [[ "$quiet_flag" != "true" ]]; then
        echo "Creating zip archive...";
        if [ ${#exclude_patterns[@]} -gt 0 ]; then
            echo "Excluding the following patterns:"
            for pattern in "${exclude_patterns[@]}"; do
                echo "  - $pattern"
            done
        fi
    fi

    # --- 5. Zip Archive Creation ---
    local zip_exclude_args=()
    zip_exclude_args+=(-x "$site_dir_name/wp-content/updraft/*") # Add default exclude
    for pattern in "${exclude_patterns[@]}"; do
        zip_exclude_args+=(-x "$site_dir_name/$pattern*") # Add user-defined excludes
    done
    #  Create the zip in the parent directory, zipping the site directory
    if ! zip -r "$backup_filename" "$site_dir_name" "${zip_exclude_args[@]}" > /dev/null; then
        echo "Error: Failed to zip files." >&2
        rm -f "$site_dir_name/$database_file"
        cd "$original_dir"
        return 1
    fi

    #  Add wp-config.php if it exists in the site directory
    if [ -f "$site_dir_name/wp-config.php" ]; then
        zip "$backup_filename" "$site_dir_name/wp-config.php" > /dev/null
    fi

    # --- 6. Cleanup and Final Report ---
    local size
    size=$(ls -lh "$backup_filename" | awk '{print $5}')
    rm -f "$site_dir_name/$database_file"
    mv "$backup_filename" "$site_dir_name/"

    local final_backup_location="$site_dir_name/$backup_filename"

    cd "$original_dir"
    local final_backup_location="$full_target_path/$backup_filename"
    local final_url="${home_url}/${backup_filename}"

    if [[ "$format_flag" == "filename" ]]; then
        echo "$backup_filename"
        return 0
    fi
    if [[ "$quiet_flag" == "true" ]]; then
        echo "$final_url"
        return 0
    fi

    echo "-----------------------------------------------------"
    echo "✅ Full site backup complete!"
    echo "   Name: $name"
    echo "   Location: $final_backup_location"
    echo "   Size: $size"
    echo "   URL: $final_url"
    echo "-----------------------------------------------------"
    echo "When done, remember to remove the backup file."
    echo "rm -f \"$final_backup_location\""
}
# ----------------------------------------------------
#  Checkpoint Commands
#  Manages versioned checkpoints of the site's manifest.
# ----------------------------------------------------

# --- Checkpoint Base Directory ---
CHECKPOINT_BASE_DIR=""
CHECKPOINT_REPO_DIR=""
CHECKPOINT_LIST_FILE=""

# ----------------------------------------------------
#  (Helper) Reverts a specific item's files to a given checkpoint hash.
# ----------------------------------------------------
function _revert_item_to_hash() {
    local item_type="$1"      # "plugin" or "theme"
    local item_name="$2"      # e.g., "akismet"
    local target_hash="$3"    # The git hash to revert to
    local wp_content_dir="$4" # The live wp-content directory
    local repo_dir="$5"       # The path to the checkpoint git repo
    local current_hash="$6"   # The hash we are reverting FROM (for cleanup)

    # Define paths
    local item_path_in_repo="${item_type}s/${item_name}"
    local restored_source_path="${repo_dir}/${item_path_in_repo}/"
    local live_item_path="${wp_content_dir}/${item_type}s/${item_name}"

    echo "Reverting '$item_name' files to state from checkpoint ${target_hash:0:7}..."

    # Use git to restore the files *within the checkpoint repo*
    "$GIT_CMD" -C "$repo_dir" checkout "$target_hash" -- "$item_path_in_repo" &>/dev/null
    if [ $? -ne 0 ]; then
        echo "❌ Error: git checkout failed. Could not restore files from checkpoint." >&2
        # Clean up by checking out the original state before we messed with it
        "$GIT_CMD" -C "$repo_dir" checkout "$current_hash" -- "$item_path_in_repo" &>/dev/null
        return 1
    fi

    # Sync the restored files from the repo back to the live site
    echo "Syncing restored files to the live site..."

    # If the path no longer exists in the reverted repo state, it should be deleted from the live site.
    if [ ! -e "${repo_dir}/${item_path_in_repo}" ]; then
        echo "   - Item did not exist in target checkpoint. Removing from live site..."
        if [ -e "$live_item_path" ]; then
            rm -rf "$live_item_path"
            echo "   ✅ Removed '$live_item_path'."
        else
            echo "   - Already absent from live site. No action needed."
        fi
    else
        # The item existed. Sync it to the live site. This handles both updates and re-additions.
        echo "   - Item existed in target checkpoint. Syncing files..."
        rsync -a --delete "$restored_source_path" "$live_item_path/"
        echo "   ✅ Synced files to '$live_item_path/'."
    fi

    # IMPORTANT: Revert the repo back to the original hash so it remains consistent.
    # This resets the state of the repo, leaving only the live files changed.
    "$GIT_CMD" -C "$repo_dir" checkout "$current_hash" -- "$item_path_in_repo" &>/dev/null

    echo "✅ Revert complete for '$item_name'."
    echo "💡 Note: This action reverts files only. Database or activation status changes are not affected."
}

# ----------------------------------------------------
#  Ensures checkpoint directories and lists exist.
# ----------------------------------------------------
function _ensure_checkpoint_setup() {
    # Exit if already initialized
    if [[ -n "$CHECKPOINT_BASE_DIR" ]]; then return 0; fi

    local private_dir
    if ! private_dir=$(_get_private_dir); then
        return 1
    fi

    CHECKPOINT_BASE_DIR="${private_dir}/checkpoints"
    CHECKPOINT_REPO_DIR="$CHECKPOINT_BASE_DIR/repo"
    CHECKPOINT_LIST_FILE="$CHECKPOINT_BASE_DIR/list.json"

    mkdir -p "$CHECKPOINT_REPO_DIR"
    if [ ! -f "$CHECKPOINT_LIST_FILE" ]; then
        echo "[]" > "$CHECKPOINT_LIST_FILE" 
    fi
}

# ----------------------------------------------------
#  Generates a JSON manifest of the current WP state and saves it to a file.
# ----------------------------------------------------
function _generate_manifest() {
    local output_file="$1"
    if [ -z "$output_file" ]; then
        echo "Error: No output file provided to _generate_manifest." >&2
        return 1
    fi

    local core_version; core_version=$("$WP_CLI_CMD" core version --skip-plugins --skip-themes)
    local plugins; plugins=$("$WP_CLI_CMD" plugin list --fields=name,title,status,version,auto_update --format=json --skip-plugins --skip-themes)
    local themes; themes=$("$WP_CLI_CMD" theme list --fields=name,title,status,version,auto_update --format=json --skip-plugins --skip-themes)

    # Manually create JSON to avoid extra dependencies
    cat <<EOF > "$output_file"
{
  "core": "$core_version",
  "plugins": $plugins,
  "themes": $themes
}
EOF
}

# ----------------------------------------------------
#  Creates a new checkpoint.
# ----------------------------------------------------
function checkpoint_create() {
    if ! setup_git; then return 1; fi
    if ! setup_wp_cli; then echo "❌ Error: WP-CLI not found." >&2; return 1; fi
    if ! command -v rsync &>/dev/null; then echo "❌ Error: rsync command not found." >&2; return 1; fi

    _ensure_checkpoint_setup

    echo "🚀 Creating new checkpoint..."

    # Get wp-content path
    local wp_content_dir
    wp_content_dir=$("$WP_CLI_CMD" eval "echo rtrim(WP_CONTENT_DIR, '/');" --skip-plugins --skip-themes 2>/dev/null)
    if [ -z "$wp_content_dir" ] || [ ! -d "$wp_content_dir" ]; then
        echo "❌ Error: Could not determine wp-content directory." >&2
        return 1
    fi
    echo "   - Found wp-content at: $wp_content_dir"

    # Sync files
    echo "   - Syncing themes, plugins, and mu-plugins..."
    mkdir -p "$CHECKPOINT_REPO_DIR/themes" "$CHECKPOINT_REPO_DIR/plugins" "$CHECKPOINT_REPO_DIR/mu-plugins"

    # Use rsync to copy directories. The trailing slashes are important.
    rsync -a --delete --exclude='*.zip' --exclude='logs/' --exclude='.git/' "$wp_content_dir/themes/" "$CHECKPOINT_REPO_DIR/themes/"
    rsync -a --delete --exclude='*.zip' --exclude='logs/' --exclude='.git/' "$wp_content_dir/plugins/" "$CHECKPOINT_REPO_DIR/plugins/"
    if [ -d "$wp_content_dir/mu-plugins" ]; then
      rsync -a --delete --exclude='*.zip' --exclude='logs/' --exclude='.git/' "$wp_content_dir/mu-plugins/" "$CHECKPOINT_REPO_DIR/mu-plugins/"
    fi

    local manifest_file="$CHECKPOINT_REPO_DIR/manifest.json"

    echo "   - Generating manifest..."
    if ! _generate_manifest "$manifest_file"; then
        echo "❌ Error: Failed to generate manifest file." >&2
        return 1
    fi

    # Initialize git repo if it doesn't exist
    if [ ! -d "$CHECKPOINT_REPO_DIR/.git" ]; then
        echo "   - Initializing checkpoint repository..."
        "$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" init -b main > /dev/null
    fi

    echo "   - Committing changes to repository..."
    # Add all changes (manifest + files)
    "$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" add .
    # Check if there are changes to commit
    if "$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" diff --staged --quiet; then
        echo "✅ No changes detected. Checkpoint is up-to-date."
        local latest_hash; latest_hash=$("$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" rev-parse HEAD 2>/dev/null)
        if [ -n "$latest_hash" ]; then
            echo "   Latest Hash: $latest_hash"
        fi
        return 0
    fi
    
    # Set a default author identity for the commit to prevent errors on remote systems
    # where git might not be configured. This is a local config for this repo only.
    "$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" config user.email "script@captaincore.io"
    "$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" config user.name "_do Script"

    local timestamp; timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
    "$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" commit -m "Checkpoint $timestamp" > /dev/null
    if [ $? -ne 0 ]; then
        echo "❌ Error: Failed to commit checkpoint changes." >&2
        return 1
    fi
    
    local commit_hash; commit_hash=$("$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" rev-parse HEAD)
    if [ -z "$commit_hash" ]; then
        echo "❌ Error: Could not retrieve commit hash after creating checkpoint." >&2
        return 1
    fi

    local checkpoint_file="$CHECKPOINT_BASE_DIR/$commit_hash.json"

    echo "   - Saving checkpoint details..."
    printf '{\n  "hash": "%s",\n  "timestamp": "%s"\n}\n' "$commit_hash" "$timestamp" > "$checkpoint_file"

    # Safely update the JSON list file using a PHP script
    local php_code_template='
<?php
$list_file = "%s";
$hash = "%s";
$timestamp = "%s";
$list = file_exists($list_file) ? json_decode(file_get_contents($list_file), true) : [];
if (!is_array($list)) { $list = []; }
$new_entry = ["hash" => $hash, "timestamp" => $timestamp];
array_unshift($list, $new_entry);
echo json_encode($list, JSON_PRETTY_PRINT);
'
    local php_script; php_script=$(printf "$php_code_template" "$CHECKPOINT_LIST_FILE" "$commit_hash" "$timestamp")
    
    local temp_list_file; temp_list_file=$(mktemp)
    if echo "$php_script" | "$WP_CLI_CMD" eval-file - > "$temp_list_file"; then
        mv "$temp_list_file" "$CHECKPOINT_LIST_FILE"
    else
        echo "❌ Error: Failed to update checkpoint list." >&2
        rm "$temp_list_file"
    fi
    
    echo "✅ Checkpoint created successfully."
    echo "   Hash: $commit_hash"
    
    # Automatically regenerate the detailed checkpoint list
    echo "   - Regenerating detailed checkpoint list..."
    checkpoint_list_generate > /dev/null
}

# ----------------------------------------------------
#  Generates a detailed list of checkpoints for faster access.
# ----------------------------------------------------
function checkpoint_list_generate() {
    if ! setup_gum || ! setup_git; then return 1; fi
    if ! setup_wp_cli; then return 1; fi
    _ensure_checkpoint_setup

    # Read the potentially simple list created by `checkpoint create`
    local php_script_read_list='
<?php
$list_file = "%s";
if (!file_exists($list_file)) { return; }
$list = json_decode(file_get_contents($list_file), true);
if (!is_array($list) || empty($list)) { return; }
foreach($list as $item) {
    if (isset($item["timestamp"]) && isset($item["hash"])) {
        echo $item["timestamp"] . "|" . $item["hash"] . "\n";
    }
}
'
    local php_script; php_script=$(printf "$php_script_read_list" "$CHECKPOINT_LIST_FILE")
    local checkpoint_entries; checkpoint_entries=$(echo "$php_script" | "$WP_CLI_CMD" eval-file -)

    if [ -z "$checkpoint_entries" ]; then
        echo "ℹ️  No checkpoints found to generate a list from."
        return 0
    fi
    
    echo "🔎 Generating detailed checkpoint list... (This may take a moment)"
    local detailed_items=()

    while IFS='|' read -r timestamp hash; do
        hash=$(echo "$hash" | tr -d '[:space:]')
        if [ -z "$hash" ]; then continue; fi

        local parent_hash=$("$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" log -n 1 --pretty=format:%P "$hash" 2>/dev/null)
        local manifest_current; manifest_current=$("$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" show "$hash:manifest.json" 2>/dev/null)
        if [ -z "$manifest_current" ]; then continue; fi

        local php_get_counts='
<?php
$manifest_json = <<<'EOT'
%s
EOT;
$data = json_decode($manifest_json, true);
$theme_count = isset($data["themes"]) && is_array($data["themes"]) ? count($data["themes"]) : 0;
$plugin_count = isset($data["plugins"]) && is_array($data["plugins"]) ? count($data["plugins"]) : 0;
echo "$theme_count Themes, $plugin_count Plugins";
'
        local counts_script; counts_script=$(printf "$php_get_counts" "$manifest_current")
        local counts_str; counts_str=$(echo "$counts_script" | "$WP_CLI_CMD" eval-file -)
        
        local diff_stats="Initial checkpoint"
        if [ -n "$parent_hash" ]; then
            diff_stats=$("$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" diff --shortstat "$parent_hash" "$hash" -- 'plugins/' 'themes/' 'mu-plugins/' | sed 's/^[ \t]*//')
            if [ -z "$diff_stats" ]; then diff_stats="No file changes"; fi
        fi

        local formatted_timestamp
        if [[ "$(uname)" == "Darwin" ]]; then
            formatted_timestamp=$(date -j -f "%Y-%m-%dT%H:%M:%SZ" -u "$timestamp" "+%a, %b %d, %Y, %-I:%M %p")
        else
            formatted_timestamp=$(date -d "$timestamp" "+%a, %b %d, %Y, %-I:%M %p")
        fi

        # Create a JSON object for this item
        local json_item
        json_item=$(printf '{"hash": "%s", "timestamp": "%s", "formatted_timestamp": "%s", "counts_str": "%s", "diff_stats": "%s"}' \
            "$hash" "$timestamp" "$formatted_timestamp" "$counts_str" "$diff_stats")
        
        detailed_items+=("$json_item")

    done <<< "$checkpoint_entries"
    
    # Write the detailed list back to the file
    local full_json="["
    full_json+=$(IFS=,; echo "${detailed_items[*]}")
    full_json+="]"

    # Use PHP to pretty-print the JSON to the file
    local php_write_script='
<?php
$list_file = "%s";
$json_data = <<<'EOT'
%s
EOT;
$data = json_decode($json_data, true);
file_put_contents($list_file, json_encode($data, JSON_PRETTY_PRINT));
'
    local write_script; write_script=$(printf "$php_write_script" "$CHECKPOINT_LIST_FILE" "$full_json")
    if echo "$write_script" | "$WP_CLI_CMD" eval-file -; then
        echo "✅ Detailed checkpoint list saved to $CHECKPOINT_LIST_FILE"
    else
        echo "❌ Error: Failed to write detailed list."
    fi
}

# ----------------------------------------------------
#  (Helper) Lets the user select a checkpoint hash from the list.
# ----------------------------------------------------
function _select_checkpoint_hash() {
    _ensure_checkpoint_setup
    if ! setup_wp_cli; then return 1; fi

    if [ ! -s "$CHECKPOINT_LIST_FILE" ]; then
        echo "ℹ️ No checkpoints found. Run '_do checkpoint create' to make one." >&2
        exit 1
    fi
    
    # Use PHP to read the detailed list and check if it's in the new format
    local php_script_read_list='
<?php
$list_file = "%s";
$list = json_decode(file_get_contents($list_file), true);

if (!is_array($list) || empty($list)) {
    echo "EMPTY";
    return;
}

// Check if the first item has the detailed format.
if (!isset($list[0]["formatted_timestamp"])) {
    echo "NEEDS_GENERATE";
    return;
}

foreach($list as $item) {
    if (isset($item["formatted_timestamp"]) && isset($item["hash"]) && isset($item["counts_str"]) && isset($item["diff_stats"])) {
        // Output format: formatted_timestamp|hash|counts_str|diff_stats
        echo $item["formatted_timestamp"] . "|" . $item["hash"] . "|" . $item["counts_str"] . "|" . $item["diff_stats"] . "\n";
    }
}
'
    local php_script; php_script=$(printf "$php_script_read_list" "$CHECKPOINT_LIST_FILE")
    local checkpoint_entries; checkpoint_entries=$(echo "$php_script" | "$WP_CLI_CMD" eval-file -)

    if [[ "$checkpoint_entries" == "EMPTY" ]]; then
        echo "ℹ️  No checkpoints available to select." >&2
        exit 1 # Use exit 1 to guarantee a non-zero exit code from the subshell
    elif [[ "$checkpoint_entries" == "NEEDS_GENERATE" ]]; then
        echo "⚠️ The checkpoint list needs to be generated for faster display." >&2
        echo "Please run: _do checkpoint list-generate" >&2
        exit 1 # Use exit 1
    fi

    local display_items=()
    local data_items=()

    # Get terminal width for dynamic padding
    local term_width; term_width=$(tput cols)
    local hash_col_width=9 # "xxxxxxx |"
    local counts_col_width=20 # "xx Themes, xx Plugins |"
    
    # Calculate available width for the timestamp column
    local timestamp_col_width=$((term_width - hash_col_width - counts_col_width - 5)) # 5 for buffers
    # Set a reasonable minimum and maximum
    if [ "$timestamp_col_width" -lt 20 ]; then timestamp_col_width=20; fi
    if [ "$timestamp_col_width" -gt 30 ]; then timestamp_col_width=30; fi

    while IFS='|' read -r formatted_timestamp hash counts_str diff_stats; do
        hash=$(echo "$hash" | tr -d '[:space:]')
        if [ -z "$hash" ]; then continue; fi

        # Use the new dynamic width for the timestamp
        local display_string
        display_string=$(printf "%-${timestamp_col_width}s | %s | %-18s | %s" \
            "$formatted_timestamp" "${hash:0:7}" "$counts_str" "$diff_stats")
        
        display_items+=("$display_string")
        data_items+=("$hash")
    done <<< "$checkpoint_entries"
    
    if [ ${#display_items[@]} -eq 0 ]; then
      echo "❌ No valid checkpoints to display." >&2
      exit 1
    fi

    local prompt_text="${1:-Select a checkpoint to inspect}"
    local selected_display
    selected_display=$(printf "%s\n" "${display_items[@]}" | "$GUM_CMD" filter --height=20 --prompt="👇 $prompt_text" --indicator="→" --placeholder="")

    if [ -z "$selected_display" ]; then
        echo "" # Return empty for cancellation
        return 0
    fi

    local selected_index=-1
    for i in "${!display_items[@]}"; do
       if [[ "${display_items[$i]}" == "$selected_display" ]]; then
           selected_index=$i
           break
       fi
    done

    if [ "$selected_index" -ne -1 ]; then
        echo "${data_items[$selected_index]}"
        return 0
    else
        echo "❌ Error: Could not find selected checkpoint." >&2
        exit 1
    fi
}

# ----------------------------------------------------
#  Lists all checkpoints from the pre-generated list and allows selection.
# ----------------------------------------------------
function checkpoint_list() {
    if ! setup_gum || ! setup_git; then return 1; fi
    
    local selected_hash
    selected_hash=$(_select_checkpoint_hash "Select a checkpoint to inspect")
    local exit_code=$?

    if [ $exit_code -ne 0 ]; then
        return 1
    fi

    if [ -z "$selected_hash" ]; then
        echo "No checkpoint selected."
        return 0
    fi

    checkpoint_show "$selected_hash"
}

# ----------------------------------------------------
#  Reverts all files to a specific checkpoint hash.
# ----------------------------------------------------
function checkpoint_revert() {
    local target_hash="$1"

    if ! setup_gum || ! setup_git; then return 1; fi
    if ! setup_wp_cli; then return 1; fi

    # If no hash is provided, let the user pick one from a detailed list.
    if [ -z "$target_hash" ]; then
        target_hash=$(_select_checkpoint_hash "Select a checkpoint to revert to")
        
        if [ -z "$target_hash" ]; then
            echo "Revert cancelled."
            return 0
        fi
        # Check the exit code of the helper
        if [ $? -ne 0 ]; then
            return 1 # Error was already printed by the helper
        fi
    fi
    
    _ensure_checkpoint_setup

    # Validate the hash to ensure it exists in the repo before proceeding
    if ! "$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" cat-file -e "${target_hash}^{commit}" &>/dev/null; then
        echo "❌ Error: Checkpoint hash '$target_hash' not found." >&2
        return 1
    fi

    # Final confirmation before the revert
    echo "🚨 You are about to revert ALL themes, plugins, and mu-plugins to the state from checkpoint ${target_hash:0:7}."
    echo "This will overwrite any changes made since that checkpoint was created."
    "$GUM_CMD" confirm "Are you sure you want to proceed?" || { echo "Revert cancelled."; return 0; }

    # Get wp-content path for rsync destination
    local wp_content_dir
    wp_content_dir=$("$WP_CLI_CMD" eval "echo rtrim(WP_CONTENT_DIR, '/');" --skip-plugins --skip-themes 2>/dev/null)
    if [ -z "$wp_content_dir" ] || [ ! -d "$wp_content_dir" ]; then
        echo "❌ Error: Could not determine wp-content directory." >&2
        return 1
    fi
    
    local current_hash=$("$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" rev-parse HEAD)

    # Revert all three directories within the git repo
    echo "Reverting all tracked files to checkpoint ${target_hash:0:7}..."
    "$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" checkout "$target_hash" -- 'plugins/' 'themes/' 'mu-plugins/' &>/dev/null
    
    # Sync the reverted files from the repo to the live site directories
    echo "Syncing restored files to the live site..."
    rsync -a --delete "$CHECKPOINT_REPO_DIR/plugins/" "$wp_content_dir/plugins/"
    rsync -a --delete "$CHECKPOINT_REPO_DIR/themes/" "$wp_content_dir/themes/"
    rsync -a --delete "$CHECKPOINT_REPO_DIR/mu-plugins/" "$wp_content_dir/mu-plugins/"

    # IMPORTANT: Reset the repo's state back to the original `HEAD`
    "$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" checkout "$current_hash" -- 'plugins/' 'themes/' 'mu-plugins/' &>/dev/null

    echo "✅ Full file revert to checkpoint ${target_hash:0:7} is complete."
    echo "💡 Note: This action reverts files only. Database changes, plugin/theme activation status, and WordPress core version are not affected."
}

# ----------------------------------------------------
#  Shows the diff between two checkpoints or one checkpoint and its parent.
# ----------------------------------------------------
function checkpoint_show() {
    local hash_after="$1"
    local hash_before="$2"

    if [ -z "$hash_after" ]; then
        echo "❌ Error: No hash provided." >&2
        show_command_help "checkpoint"
        return 1
    fi

    if ! setup_gum || ! setup_git; then return 1; fi
    if ! setup_wp_cli; then return 1; fi
    _ensure_checkpoint_setup

    # If 'before' hash is not provided, find the parent of the 'after' hash.
    if [ -z "$hash_before" ]; then
        hash_before=$("$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" log -n 1 --pretty=format:%P "$hash_after" 2>/dev/null)
    fi

    local manifest_after
    manifest_after=$("$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" show "$hash_after:manifest.json" 2>/dev/null)
    if [ -z "$manifest_after" ]; then
        echo "❌ Error: Could not find manifest for 'after' hash '$hash_after'." >&2
        return 1
    fi

    local manifest_before="{}"
    if [ -n "$hash_before" ]; then
        manifest_before=$("$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" show "$hash_before:manifest.json" 2>/dev/null)
        if [ -z "$manifest_before" ]; then
            echo "⚠️ Warning: Could not find manifest for 'before' hash '$hash_before'. Comparing against an empty state." >&2
            manifest_before="{}"
        fi
    fi

    # Get a list of themes and plugins that have actual file changes.
    local changed_files_list
    if [ -z "$hash_before" ]; then
        # This is the initial commit, compare against the empty tree.
        changed_files_list=$("$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" diff-tree --no-commit-id --name-only -r "$hash_after" -- 'plugins/' 'themes/' 'mu-plugins/')
    else
        changed_files_list=$("$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" diff --name-only "$hash_before" "$hash_after" -- 'plugins/' 'themes/' 'mu-plugins/')
    fi

    local items_with_file_changes=()
    while IFS= read -r file_path; do
        if [[ -n "$file_path" ]]; then
            local item_name
            item_name=$(echo "$file_path" | cut -d'/' -f2)
            items_with_file_changes+=("$item_name")
        fi
    done <<< "$changed_files_list"
    local changed_items_str
    changed_items_str=$(printf "%s\n" "${items_with_file_changes[@]}" | sort -u | tr '\n' ',' | sed 's/,$//')

    # --- 1. Generate list of ALL items from PHP ---
    export MANIFEST_AFTER_JSON="$manifest_after"
    export MANIFEST_BEFORE_JSON="$manifest_before"
    export CHANGED_ITEMS_STR="$changed_items_str"

    local php_script
    read -r -d '' php_script <<'PHP'
<?php
// This PHP script compares two manifest files and outputs pipe-delimited data for shell processing.

$manifest_after_json = getenv('MANIFEST_AFTER_JSON');
$manifest_before_json = getenv('MANIFEST_BEFORE_JSON');
$changed_items_str = getenv('CHANGED_ITEMS_STR');

$after_data = json_decode($manifest_after_json, true);
$before_data = json_decode($manifest_before_json, true);
$items_with_file_changes = !empty($changed_items_str) ? explode(',', $changed_items_str) : [];

function process_item_diff($item_type, $after_items, $before_items, $items_with_file_changes) {
    $after_map = [];
    if (is_array($after_items)) { foreach ($after_items as $item) { if(isset($item["name"])) $after_map[$item["name"]] = $item; } }

    $before_map = [];
    if (is_array($before_items)) { foreach ($before_items as $item) { if(isset($item["name"])) $before_map[$item["name"]] = $item; } }

    $all_names = array_unique(array_merge(array_keys($after_map), array_keys($before_map)));
    sort($all_names);
    
    $output_lines = [];

    foreach ($all_names as $name) {
        if(empty($name)) continue;

        $has_changed = false;
        $change_parts = [];
        $after_item = $after_map[$name] ?? null;
        $before_item = $before_map[$name] ?? null;

        if ($after_item && $before_item) {
            // Check for status changes first for correct ordering
            if (($after_item["status"] ?? null) !== ($before_item["status"] ?? null)) {
                $change_parts[] = "status " . ($before_item["status"] ?? 'N/A') . " -> " . ($after_item["status"] ?? 'N/A');
                $has_changed = true;
            }
            if (($after_item["version"] ?? null) !== ($before_item["version"] ?? null)) {
                $change_parts[] = "version " . ($before_item["version"] ?? 'N/A') . " -> " . ($after_item["version"] ?? 'N/A');
                $has_changed = true;
            }
            if (in_array($name, $items_with_file_changes, true)) {
                $change_parts[] = "files changed";
                $has_changed = true;
            }
        } elseif ($after_item) {
            $change_parts[] = "installed";
            if(isset($after_item["version"])) $change_parts[] = "v" . $after_item["version"];
            $has_changed = true;
        } else {
            $change_parts[] = "deleted";
            $has_changed = true;
        }

        $item_for_details = $after_item ?: $before_item;
        $title = $item_for_details["title"] ?? $name;
        
        if ($has_changed) {
            $details_string = implode(", ", array_unique($change_parts));
        } else {
            $version = $item_for_details["version"] ?? 'N/A';
            $status = $item_for_details["status"] ?? 'N/A';
            // Format with status first, then version
            $details_string = "$status, v$version";
        }
        
        $output_lines[] = [
            'has_changed' => $has_changed,
            'type'        => $item_type,
            'slug'        => $name,
            'title'       => $title,
            'details'     => $details_string,
        ];
    }

    // Sort to show changed items first
    usort($output_lines, function ($a, $b) {
        if ($a['has_changed'] !== $b['has_changed']) {
            return $b['has_changed'] <=> $a['has_changed'];
        }
        return strcmp($a['slug'], $b['slug']);
    });

    // Output as pipe-delimited data
    foreach ($output_lines as $line) {
        echo implode("|", [
            $line['has_changed'] ? 'true' : 'false',
            $line['type'],
            $line['slug'],
            $line['title'],
            $line['details']
        ]) . "\n";
    }
}

process_item_diff('Theme', $after_data['themes'] ?? [], $before_data['themes'] ?? [], $items_with_file_changes);
process_item_diff('Plugin', $after_data['plugins'] ?? [], $before_data['plugins'] ?? [], $items_with_file_changes);
PHP

    local php_output
    php_output=$(echo "$php_script" | "$WP_CLI_CMD" eval-file - 2>/dev/null)

    # Unset the environment variables
    unset MANIFEST_AFTER_JSON
    unset MANIFEST_BEFORE_JSON
    unset CHANGED_ITEMS_STR

    if [ -z "$php_output" ]; then
        echo "✅  No manifest changes found between checkpoints ${hash_before:0:7} and ${hash_after:0:7}."
        return 0
    fi
    
    local display_items=()
    local data_items=()

    # Use fixed-width columns for consistent alignment
    local slug_width=30
    local title_width=42

    # Read the pipe-delimited output from PHP and format it for display
    while IFS='|' read -r has_changed item_type slug title details; do
        local icon
        if [[ "$has_changed" == "true" ]];
        then
            icon="+"
        else
            icon=$(printf '\xE2\xA0\x80\xE2\xA0\x80')
        fi

        # Use "%-2s" to create a 2-character wide column for the icon.
        # This ensures consistent padding for both the "+" and " " cases.
        # Note the space between "%-2s" and "%-8s" is preserved.
        local display_line
        display_line=$(printf "%-2s%-8s %-*.*s %-*.*s %s" "$icon" "$item_type" "$slug_width" "$slug_width" "$slug" "$title_width" "$title_width" "$title" "$details")

        display_items+=("$display_line")
        data_items+=("$item_type|$slug")
    done <<< "$php_output"

    # Start a loop to allow returning to the item selection.
    while true; do
        # --- 2. Interactive Item Selection ---
        local selected_display_text
        selected_display_text=$(printf "%s\n" "${display_items[@]}" | "$GUM_CMD" filter --prompt="? Select item to inspect (checkpoints ${hash_before:0:7} -> ${hash_after:0:7}). Press Esc to exit." --height=20 --indicator="→" --placeholder="")

        if [ -z "$selected_display_text" ]; then
            # User pressed Esc, so break the loop and exit the function.
            break
        fi

        local selected_index=-1
        for i in "${!display_items[@]}"; do
           if [[ "${display_items[$i]}" == "$selected_display_text" ]]; then
               selected_index=$i
               break
           fi
        done

        if [ "$selected_index" -eq -1 ]; then
            # Should not happen, but as a safeguard
            continue
        fi

        local item_data="${data_items[$selected_index]}"
        local item_type; item_type=$(echo "$item_data" | cut -d'|' -f1)
        local item_name; item_name=$(echo "$item_data" | cut -d'|' -f2)

        # --- 3. Get wp-content Path ---
        local wp_content_dir
        wp_content_dir=$("$WP_CLI_CMD" eval "echo rtrim(WP_CONTENT_DIR, '/');" --skip-plugins --skip-themes 2>/dev/null)
        if [ -z "$wp_content_dir" ] || [ ! -d "$wp_content_dir" ]; then
            echo "❌ Error: Could not determine wp-content directory." >&2
            return 1
        fi

        # --- 4. Interactive Action Selection ---
        local choices=("Show File Changes" "Revert Files to 'After' State (${hash_after:0:7})")
        if [ -n "$hash_before" ]; then
            choices+=("Revert Files to 'Before' State (${hash_before:0:7})")
        fi
        choices+=("Back to item list")
        
        local action; action=$("$GUM_CMD" choose "${choices[@]}")

        # --- 5. Execute Action ---
        case "$action" in
            "Show File Changes")
                local item_path_in_repo
                case "$item_type" in
                    "Theme")
                        item_path_in_repo="themes/${item_name}"
                        ;;
                    "Plugin")
                        item_path_in_repo="plugins/${item_name}"
                        ;;
                esac
                
                # Get the list of files that have changed for the selected item.
                local changed_files
                if [ -z "$hash_before" ]; then
                    changed_files=$("$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" diff-tree --no-commit-id --name-only -r "$hash_after" -- "$item_path_in_repo")
                else
                    changed_files=$("$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" diff --name-only "$hash_before" "$hash_after" -- "$item_path_in_repo")
                fi

                if [ -z "$changed_files" ]; then
                    "$GUM_CMD" spin --spinner dot --title "No file changes found for '$item_name'." -- sleep 3
                else
                    echo "Showing file changes for '$item_name' between ${hash_before:0:7} and ${hash_after:0:7}."

                    # Loop to allow viewing multiple diffs
                    while true; do
                        clear
                        local selected_file
                        selected_file=$(echo "$changed_files" | "$GUM_CMD" filter --prompt="? Select a file to view its diff (Press Esc to exit)" --height=20 --indicator="→" --placeholder="")

                        if [ -z "$selected_file" ]; then
                            break
                        fi
                        
                        # Show the diff for the selected file, piped to `less`.
                        if [ -z "$hash_before" ]; then
                             # For the initial commit, just show the file content as it was added.
                            "$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" --no-pager show --color=always "$hash_after" -- "$selected_file" | less -RX
                        else
                            "$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" --no-pager diff --color=always "$hash_before" "$hash_after" -- "$selected_file" | less -RX
                        fi
                    done
                fi
                ;;
            "Revert Files to 'After' State ("*)
                _revert_item_to_hash "$item_type" "$item_name" "$hash_after" "$wp_content_dir" "$CHECKPOINT_REPO_DIR" "$hash_after"
                ;;
            "Revert Files to 'Before' State ("*)
                 if [ -z "$hash_before" ]; then
                    echo "❌ Cannot revert: 'Before' state does not exist (likely the first checkpoint)." >&2
                    return 1
                 fi
                _revert_item_to_hash "$item_type" "$item_name" "$hash_before" "$wp_content_dir" "$CHECKPOINT_REPO_DIR" "$hash_after"
                ;;
            "Back to item list"|*)
                # Do nothing, the loop will continue to the next iteration.
                continue
                ;;
        esac
    done
}

# ----------------------------------------------------
#  Gets the latest checkpoint hash.
# ----------------------------------------------------
function checkpoint_latest() {
    _ensure_checkpoint_setup
    if ! setup_wp_cli; then return 1; fi
    if [ ! -s "$CHECKPOINT_LIST_FILE" ]; then
        echo "ℹ️ No checkpoints found."
        return
    fi
    
    local php_code_template='
<?php
$list_file = "%s";
if (!file_exists($list_file)) { return; }
$list = json_decode(file_get_contents($list_file));
if (!empty($list) && isset($list[0]->hash)) {
    echo $list[0]->hash;
}
'
    local php_script; php_script=$(printf "$php_code_template" "$CHECKPOINT_LIST_FILE")
    local latest_hash
    latest_hash=$(echo "$php_script" | "$WP_CLI_CMD" eval-file -)

    if [ -z "$latest_hash" ]; then
        echo "ℹ️ No checkpoints found."
    else
        echo "$latest_hash"
    fi
}

# ----------------------------------------------------
#  Cleans up inactive themes.
# ----------------------------------------------------
function clean_themes() {
    # --- Pre-flight checks ---
    if ! setup_wp_cli; then echo "❌ Error: WP-CLI not found." >&2; return 1; fi
    if ! "$WP_CLI_CMD" core is-installed --quiet; then echo "❌ Error: This does not appear to be a WordPress installation." >&2; return 1; fi

    echo "🔎 Finding the latest default WordPress theme to preserve..."
    latest_default_theme=$("$WP_CLI_CMD" theme search twenty --field=slug --per-page=1 --quiet --skip-plugins --skip-themes)

    if [ $? -ne 0 ] || [ -z "$latest_default_theme" ]; then
      echo "❌ Error: Could not determine the latest default theme. Aborting." >&2
      return 1
    fi
    echo "✅ The latest default theme is '$latest_default_theme'. This will be preserved."
    inactive_themes=($("$WP_CLI_CMD" theme list --status=inactive --field=name --skip-plugins --skip-themes))
    if [ ${#inactive_themes[@]} -eq 0 ]; then
      echo "👍 No inactive themes found to process. All done!"
      return 0
    fi

    echo "🚀 Processing ${#inactive_themes[@]} inactive themes..."
    for theme in "${inactive_themes[@]}"; do
      # Check if the current inactive theme is the one we want to keep
      if [[ "$theme" == "$latest_default_theme" ]]; then
        echo "⚪️ Keeping inactive default theme: $theme"
      else
        echo "❌ Deleting inactive theme: $theme"
        "$WP_CLI_CMD" theme delete "$theme"
      fi
    done

    echo "✨ Cleanup complete."
}

# ----------------------------------------------------
#  Deletes inactive plugins.
#  On multisite, only deletes plugins not active on any site.
# ----------------------------------------------------
function clean_plugins() {
    # --- Pre-flight checks ---
    if ! setup_wp_cli; then echo "❌ Error: WP-CLI not found." >&2; return 1; fi
    if ! "$WP_CLI_CMD" core is-installed --quiet; then echo "❌ Error: This does not appear to be a WordPress installation." >&2; return 1; fi
    if ! setup_gum; then return 1; fi

    echo "🚀 Cleaning inactive plugins..."

    # --- Multisite vs. Single Site Logic ---
    if "$WP_CLI_CMD" core is-installed --network --quiet; then
        echo "ℹ️ Multisite installation detected. Finding plugins that are not active on any site..."

        # Get all installed plugins (slugs)
        local all_installed_plugins
        all_installed_plugins=$("$WP_CLI_CMD" plugin list --field=name)

        # Get all network-activated plugins
        local network_active_plugins
        network_active_plugins=$("$WP_CLI_CMD" plugin list --network --status=active --field=name)

        # Get all plugins active on individual sites
        local site_active_plugins
        site_active_plugins=$("$WP_CLI_CMD" site list --field=url --format=ids | xargs -I % "$WP_CLI_CMD" plugin list --url=% --status=active --field=name)

        # Combine all active plugins (network + site-specific) and get a unique, sorted list
        local all_active_plugins
        all_active_plugins=$(echo -e "${network_active_plugins}\n${site_active_plugins}" | sort -u | grep -v '^$')

        # Find plugins that are in the installed list but not in the combined active list
        local plugins_to_delete
        plugins_to_delete=$(comm -23 <(echo "$all_installed_plugins" | sort) <(echo "$all_active_plugins" | sort))

    else
        echo "ℹ️ Single site installation detected. Finding inactive plugins..."
        # On a single site, 'inactive' is sufficient
        local plugins_to_delete
        plugins_to_delete=$("$WP_CLI_CMD" plugin list --status=inactive --field=name)
    fi

    if [ -z "$plugins_to_delete" ]; then
        echo "✅ No inactive plugins found to delete."
        return 0
    fi

    local plugins_to_delete_count
    plugins_to_delete_count=$(echo "$plugins_to_delete" | wc -l | xargs)

    echo "🔎 Found ${plugins_to_delete_count} plugin(s) to delete:"
    echo "$plugins_to_delete"
    echo

    if ! "$GUM_CMD" confirm "Proceed with deletion?"; then
        echo "Operation cancelled by user."
        return 0
    fi

    while IFS= read -r plugin; do
        if [ -n "$plugin" ]; then
            echo "   - Deleting '$plugin'..."
            "$WP_CLI_CMD" plugin delete "$plugin"
        fi
    done <<< "$plugins_to_delete"

    echo "✨ Plugin cleanup complete."
}

# ----------------------------------------------------
#  Analyzes disk usage using rclone.
# ----------------------------------------------------
function clean_disk() {
    echo "🚀 Launching interactive disk usage analysis..."
    if ! setup_rclone; then
        echo "Aborting analysis: rclone setup failed." >&2
        return 1
    fi
    "$RCLONE_CMD" ncdu .
}
# ----------------------------------------------------
#  Finds large images and converts them to the
#  WebP format.
# ----------------------------------------------------
function convert_to_webp() {
    # The target directory is the first positional argument.
    # The --all flag is passed as the second argument from main.
    local target_dir_arg="$1"
    local all_files_flag="$2"
    echo "🚀 Starting WebP Conversion Process 🚀"

    # --- Pre-flight Checks ---
    if ! setup_cwebp; then
        echo "Aborting conversion: cwebp setup failed." >&2
        return 1
    fi

    # --- Initialize and Report Identify Method ---
    # Prime the _is_webp function to determine the method and export the choice.
    _is_webp ""
    # Now that IDENTIFY_METHOD is set, report the choice to the user once.
    if [[ "$IDENTIFY_METHOD" == "identify" ]]; then
        echo "Using 'identify' command for image type checking."
    else
        echo "Warning: 'identify' command not found. Falling back to PHP check."
    fi

    # --- Determine target directory ---
    local target_dir="wp-content/uploads"
    if [ -n "$target_dir_arg" ]; then
        target_dir="$target_dir_arg"
        echo "Targeting custom directory: $target_dir"
    else
        echo "Targeting default directory: $target_dir"
    fi

    if [ ! -d "$target_dir" ]; then
        echo "❌ Error: Cannot find '$target_dir' directory." >&2
        return 1
    fi

    # --- Size and File Discovery ---
    local before_size
    before_size="$(du -sh "$target_dir" | awk '{print $1}')"
    echo "Current directory size: $before_size"

    local size_limit_mb=1
    local message="larger than ${size_limit_mb}MB"
    local find_args=("$target_dir" -type f)

    if [[ "$all_files_flag" == "true" ]]; then
        message="of all sizes"
    else
        find_args+=(-size "+${size_limit_mb}M")
    fi
    find_args+=(\( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.webp" \))

    local files
    files=$(find "${find_args[@]}")

    if [[ -z "$files" ]]; then
        echo "✅ No images ${message} found to convert."
        return 0
    fi
    local count
    count=$(echo "$files" | wc -l | xargs)
    echo "Found $count image(s) ${message} to process using up to 5 concurrent threads..."
    echo ""

    # --- Helper function for processing a single image ---
    # This function will be run in the background for each image.
    _process_single_image() {
        local file="$1"
        local current_num="$2"
        local total_num="$3"

        # The _is_webp function checks if the file is already in WebP format.
        if _is_webp "$file"; then
            echo "⚪️ Skipping ${current_num}/${total_num} (already WebP): $file"
            return
        fi

        local temp_file="${file}.temp.webp"
        local before_file_size
        before_file_size=$(ls -lh "$file" | awk '{print $5}')

        # The actual conversion command, output is suppressed for a cleaner log.
        "$CWEBP_CMD" -q 80 "$file" -o "$temp_file" > /dev/null 2>&1

        # Check if the conversion was successful and the new file has content.
        if [ -s "$temp_file" ]; then
            mv "$temp_file" "$file"
            local after_file_size
            after_file_size=$(ls -lh "$file" | awk '{print $5}')
            echo "✅ Converted ${current_num}/${total_num} ($before_file_size -> $after_file_size): $file"
        else
            # Cleanup failed temporary file and report the failure.
            rm -f "$temp_file"
            echo "❌ Failed ${current_num}/${total_num}: $file"
        fi
    }

    # Export the helper function and its dependencies so they are available to the subshells.
    export -f _process_single_image
    export -f _is_webp
    export -f _is_webp_php
    export -f setup_wp_cli

    # --- Concurrent Processing Loop ---
    local max_jobs=5
    local job_count=0
    local processed_count=0

    # Use process substitution to avoid creating a subshell for the while loop.
    # This ensures the main script's 'wait' command can see all background jobs.
    while IFS= read -r file; do
        processed_count=$((processed_count + 1))
        
        # Run the processing function in the background.
        _process_single_image "$file" "$processed_count" "$count" &

        # On Linux, use 'wait -n' for a sliding window of jobs.
        # On macOS, bash doesn't support 'wait -n', so we skip this
        # and let the final 'wait' handle all jobs at once.
        if [[ "$(uname)" != "Darwin" ]]; then
            job_count=$((job_count + 1))
            if (( job_count >= max_jobs )); then
                wait -n
                job_count=$((job_count - 1))
            fi
        fi
    done < <(echo "$files")

    # Wait for all remaining background jobs to complete before proceeding.
    wait

    # --- Final Summary ---
    echo ""
    local after_size
    after_size="$(du -sh "$target_dir" | awk '{print $1}')"
    echo "✅ Bulk conversion complete!"
    echo "-----------------------------------------------------"
    echo "   Directory size reduced from $before_size to $after_size."
    echo "-----------------------------------------------------"
}
# ----------------------------------------------------
#  Cron Commands
#  Manages scheduled tasks for the _do script.
# ----------------------------------------------------

# ----------------------------------------------------
#  (Helper) PHP script to manage cron events.
# ----------------------------------------------------
function _get_cron_manager_php_script() {
    read -r -d '' php_script <<'PHP'
<?php

$argv = WP_CLI::get_runner()->arguments;
array_shift( $argv );
// This script is a self-contained manager for cron events stored in a WP option.
// It is designed to be called with specific actions and arguments.

// Prevent direct execution.
if (empty($argv) || !isset($argv[1])) {
    return;
}

$action = $argv[1] ?? null;
// The main function for this script is to get the option, unserialize it,
// perform an action, then serialize and save the result.
function get_events() {
    // get_option will return the value of the option, already unserialized.
    // The second argument is the default value if the option does not exist.
    $events = get_option("captaincore_do_cron", []);
    return is_array($events) ? $events : [];
}

function save_events($events) {
    // update_option will create the option if it does not exist.
    // The third argument 'no' sets autoload to false.
    update_option( "captaincore_do_cron", $events, 'no');
}

// --- Action Router ---

if ($action === 'list_all') {
    $events = get_events();
    if (empty($events)) {
        return;
    }
    // Sort events by the next_run timestamp to show the soonest first.
    usort($events, function($a, $b) {
        return ($a['next_run'] ?? 0) <=> ($b['next_run'] ?? 0);
    });

    // MODIFICATION: Get the WordPress timezone once before the loop.
    $wp_timezone = wp_timezone();

    foreach ($events as $event) {
        
        // MODIFICATION: Convert the stored UTC timestamp to the WP timezone for display.
        $next_run_formatted = 'N/A';
        if (isset($event['next_run'])) {
            // Create a DateTime object from the UTC timestamp
            $next_run_dt = new DateTime("@" . $event['next_run']);
            // Set the object's timezone to the WordPress configured timezone
            $next_run_dt->setTimezone($wp_timezone);
            // Format for output
            $next_run_formatted = $next_run_dt->format('Y-m-d H:i:s T');
        }
        
        // Output in CSV format for gum table
        echo implode(',', [
            $event['id'] ?? 'N/A',
            '"' . ($event['command'] ?? 'N/A') . '"', // Quote command in case it has spaces
            $next_run_formatted,
            $event['frequency'] ?? 'N/A'
        ]) . "\n";
    }
}

elseif ($action === 'list_due') {
    $now = time();
    $due_events = [];
    foreach (get_events() as $event) {
        if (isset($event['next_run']) && $event['next_run'] <= $now) {
            $due_events[] = $event;
        }
    }
    echo json_encode($due_events);
}

elseif ($action === 'add') {
    $id = uniqid('event_');
    $command = $argv[2] ?? null; 
    $next_run_str = $argv[3] ?? null;
    $frequency = $argv[4] ?? null; 

    if (!$command || !$next_run_str || !$frequency) {
        error_log('Error: Missing arguments for add action.');
        return;
    }

    // --- Frequency Translation ---
    $freq_lower = strtolower($frequency); 
    if ($freq_lower === 'weekly') {
        $frequency = '1 week';
    } elseif ($freq_lower === 'daily') {
        $frequency = '1 day';
    } elseif ($freq_lower === 'monthly') {
        $frequency = '1 month';
    } elseif ($freq_lower === 'hourly') {
        $frequency = '1 hour';
    }
    // --- End Translation ---

    try {
        // Use the WordPress configured timezone for parsing the date string.
        $wp_timezone = wp_timezone();
        $next_run_dt = new DateTime($next_run_str, $wp_timezone);
        $next_run_timestamp = $next_run_dt->getTimestamp();
    } catch (Exception $e) {
        error_log('Error: Invalid date/time string for next_run: ' . $e->getMessage());
        return;
    }
    
    $events = get_events();
    $events[] = [ 
        'id'        => $id,
        'command'   => $command,
        'next_run'  => $next_run_timestamp,
        'frequency' => $frequency,
    ];
    save_events($events);
    echo "✅ Event '$id' added. Input '{$next_run_str}' interpreted using WordPress timezone ({$wp_timezone->getName()}). Next run: " . date('Y-m-d H:i:s T', $next_run_timestamp) . "\n";
}

elseif ($action === 'delete') {
    $id_to_delete = $argv[2] ?? null;
    if (!$id_to_delete) {
        error_log('Error: No ID provided for delete action.');
        return;
    }

    $events = get_events();
    $updated_events = [];
    $found = false;
    foreach ($events as $event) {
        if (isset($event['id']) && $event['id'] === $id_to_delete) {
            $found = true;
        } else {
            $updated_events[] = $event;
        }
    }

    if ($found) {
        save_events($updated_events);
        echo "✅ Event '$id_to_delete' deleted successfully.\n";
    } else {
        echo "❌ Error: Event with ID '$id_to_delete' not found.\n";
    }
}

elseif ($action === 'update_next_run') {
    $id = $argv[2] ?? null;
    if (!$id) {
        error_log('Error: No ID provided to update_next_run.'); 
        return;
    }

    $events = get_events(); 
    $found = false;
    foreach ($events as &$event) {
        if (isset($event['id']) && $event['id'] === $id) {
            try {
                $last_run_ts = $event['next_run'] ??
                    time();
                $next_run_dt = new DateTime("@{$last_run_ts}", new DateTimeZone('UTC'));
                
                do {
                    $next_run_dt->modify('+ ' . $event['frequency']);
                } while ($next_run_dt->getTimestamp() <= time());

                $event['next_run'] = $next_run_dt->getTimestamp(); 
                $found = true;
                break;
            } catch (Exception $e) {
                 error_log('Error: Invalid frequency string "' . ($event['frequency'] ?? '') . '": ' . $e->getMessage());
                 return;
            }
        }
    }

    if ($found) {
        save_events($events);
    }
}
PHP
    echo "$php_script"
}

# ----------------------------------------------------
#  Configures the global cron runner by installing the latest script.
# ----------------------------------------------------
function cron_enable() {
    echo "Attempting to configure cron runner..."

    if ! setup_wp_cli || ! "$WP_CLI_CMD" core is-installed --quiet; then
        echo "❌ Error: This command must be run from within a WordPress directory." >&2
        return 1
    fi
    if ! command -v realpath &> /dev/null || ! command -v md5sum &> /dev/null; then
        echo "❌ Error: 'realpath' and 'md5sum' commands are required." >&2
        return 1
    fi

    # Determine the absolute path of the WordPress installation
    local wp_path
    wp_path=$(realpath ".")
    if [[ ! -f "$wp_path/wp-load.php" ]]; then
        echo "❌ Error: Could not confirm WordPress root at '$wp_path'." >&2
        return 1
    fi

    local private_dir
    if ! private_dir=$(_get_private_dir); then return 1; fi
    local script_path="$private_dir/_do.sh"

    echo "ℹ️  Downloading the latest version of the _do script..."
    if ! command -v curl &> /dev/null; then
         echo "❌ Error: 'curl' is required to download the script." >&2; return 1;
    fi
    if ! curl -sL "https://captaincore.io/do" -o "$script_path"; then
        echo "❌ Error: Failed to download the _do script." >&2; return 1;
    fi
    chmod +x "$script_path"
    echo "✅ Script installed/updated at: $script_path"

    # Make the marker unique to the path to allow multiple cron jobs
    local path_hash
    path_hash=$(echo "$wp_path" | md5sum | cut -d' ' -f1)
    local cron_marker="#_DO_CRON_RUNNER_$path_hash"
    local cron_command="bash \"$script_path\" cron run --path=\"$wp_path\""
    local cron_job="*/10 * * * * $cron_command $cron_marker"

    # Atomically update the crontab
    local current_crontab
    current_crontab=$(crontab -l 2>/dev/null | grep -v "$cron_marker")
    (echo "$current_crontab"; echo "$cron_job") | crontab -

    if [ $? -eq 0 ]; then
        local site_url
        site_url=$("$WP_CLI_CMD" option get home --skip-plugins --skip-themes 2>/dev/null)
        echo "✅ Cron runner enabled for site: $site_url ($wp_path)"
    else
        echo "❌ Error: Could not modify crontab. Please check your permissions." >&2
        return 1
    fi

    echo "Current crontab:"
    crontab -l
}

# ----------------------------------------------------
#  Runs the cron process, executing any due events.
# ----------------------------------------------------
function cron_run() {
    # If a path is provided, change to that directory first.
    if [[ -n "$path_flag" ]]; then
        if [ -d "$path_flag" ]; then
            cd "$path_flag" || { echo "[$(date)] Cron Error: Could not change directory to '$path_flag'." >> /tmp/_do_cron.log; return 1; }
        else
            echo "[$(date)] Cron Error: Provided path '$path_flag' does not exist." >> /tmp/_do_cron.log;
            return 1
        fi
    fi

    # Call the setup function to ensure the wp command path is known.
    if ! setup_wp_cli; then
        echo "[$(date)] Cron Error: WP-CLI setup failed." >> /tmp/_do_cron.log
        return 1
    fi

    # Check if this is a WordPress installation using the full command path.
    if ! "$WP_CLI_CMD" core is-installed --quiet; then
        return 1
    fi

    local php_script;
    php_script=$(_get_cron_manager_php_script)

    local due_events_json;
    # Use the full command path for all wp-cli calls.
    due_events_json=$(echo "$php_script" | "$WP_CLI_CMD" eval-file - 'list_due' 2>&1)
    if [ $? -ne 0 ];
    then
        echo "[$(date)] Cron run failed: $due_events_json" >> /tmp/_do_cron.log
        return 1
    fi

    if [ -z "$due_events_json" ] || [[ "$due_events_json" == "[]" ]];
    then
        return 0
    fi

    local php_parser='
$json = file_get_contents("php://stdin");
$events = json_decode($json, true);
if (is_array($events)) {
    foreach($events as $event) {
        echo $event["id"] . "|" . $event["command"] . "\n";
    }
}
'
    local due_events_list;
    due_events_list=$(echo "$due_events_json" | php -r "$php_parser")

    if [ -z "$due_events_list" ];
    then
        return 0
    fi

    echo "Found due events, processing..."
    while IFS='|' read -r id command; do
        if [ -z "$id" ] || [ -z "$command" ]; then
            continue
        fi
        echo "-> Running event '$id': _do $command"
        local script_path
        script_path=$(realpath "$0")
        bash "$script_path" $command
        echo "-> Updating next run time for event '$id'"
        # Use the full command path here as well.
        echo "$php_script" | "$WP_CLI_CMD" eval-file - 'update_next_run' "$id"
    done <<< "$due_events_list"
    echo "Cron run complete."
}

# ----------------------------------------------------
#  Adds a new command to the cron schedule.
# ----------------------------------------------------
function cron_add() {
    local command="$1"
    local next_run="$2"
    local frequency="$3"

    if [ -z "$command" ] || [ -z "$next_run" ] || [ -z "$frequency" ]; then
        echo "❌ Error: Missing arguments." >&2
        show_command_help "cron"
        return 1
    fi

    if ! setup_wp_cli; then echo "❌ Error: WP-CLI not found." >&2; return 1; fi
    if ! "$WP_CLI_CMD" core is-installed --quiet; then echo "❌ Error: Not in a WordPress installation." >&2; return 1; fi

    echo "Adding new cron event..."
    local php_script; php_script=$(_get_cron_manager_php_script)

    # Capture both stdout and stderr to a variable
    local output; output=$(echo "$php_script" | "$WP_CLI_CMD" eval-file - "add" "$command" "$next_run" "$frequency" 2>&1)

    # Check the exit code of the wp-cli command
    if [ $? -ne 0 ]; then
        echo "❌ Error: The wp-cli command failed to execute."
        echo "   Output:"
        # Indent the output for readability
        echo "$output" | sed 's/^/   /'
    else
        # Print the success message from the PHP script
        echo "$output"
    fi
}

# ----------------------------------------------------
#  Deletes a scheduled cron event by its ID.
# ----------------------------------------------------
function cron_delete() {
    local event_id="$1"

    if [ -z "$event_id" ]; then
        echo "❌ Error: No event ID provided." >&2
        show_command_help "cron"
        return 1
    fi

    if ! setup_wp_cli; then echo "❌ Error: WP-CLI not found." >&2; return 1; fi
    if ! "$WP_CLI_CMD" core is-installed --quiet; then echo "❌ Error: Not in a WordPress installation." >&2; return 1; fi

    echo "Attempting to delete event '$event_id'..."
    local php_script
    php_script=$(_get_cron_manager_php_script)

    # Capture and display output from the PHP script
    local output
    output=$(echo "$php_script" | "$WP_CLI_CMD" eval-file - "delete" "$event_id" 2>&1)

    # The PHP script now prints success or error, so just display it.
    echo "$output"
}

# ----------------------------------------------------
#  Lists all scheduled cron events in a table.
# ----------------------------------------------------
function cron_list() {
    if ! setup_wp_cli; then echo "❌ Error: WP-CLI not found." >&2; return 1; fi
    if ! "$WP_CLI_CMD" core is-installed --quiet; then echo "❌ Error: Not in a WordPress installation." >&2; return 1; fi
    if ! setup_gum; then return 1; fi

    echo "🔎 Fetching scheduled events..."

    local php_script; php_script=$(_get_cron_manager_php_script)

    # Capture stdout and stderr
    local events_csv; events_csv=$(echo "$php_script" | "$WP_CLI_CMD" eval-file - 'list_all' 2>&1)

    # Check exit code
    if [ $? -ne 0 ]; then
        echo "❌ Error: The wp-cli command failed while listing events."
        echo "   Output:"
        echo "$events_csv" | sed 's/^/   /'
        return 1
    fi

    if [ -z "$events_csv" ]; then
        echo "ℹ️ No scheduled cron events found."
        return 0
    fi

    local table_header="ID,Command,Next Run,Frequency"

    # Prepend the header and pipe to gum table for a formatted view
    (echo "$table_header"; echo "$events_csv") | "$GUM_CMD" table --print --separator ","
}
# ----------------------------------------------------
#  Performs a WordPress database-only backup to a secure, private directory.
# ----------------------------------------------------
function db_backup() {
    echo "Starting database-only backup..."
    local home_directory; home_directory=$(pwd);
    local private_directory
    if ! private_directory=$(_get_private_dir); then
        return 1
    fi
    if ! setup_wp_cli; then echo "Error: wp-cli is not installed." >&2; return 1; fi
    local database_name; database_name=$("$WP_CLI_CMD" config get DB_NAME --skip-plugins --skip-themes --quiet); local database_username; database_username=$("$WP_CLI_CMD" config get DB_USER --skip-plugins --skip-themes --quiet); local database_password; database_password=$("$WP_CLI_CMD" config get DB_PASSWORD --skip-plugins --skip-themes --quiet);
    local dump_command; if command -v mariadb-dump &> /dev/null; then dump_command="mariadb-dump"; elif command -v mysqldump &> /dev/null; then dump_command="mysqldump"; else echo "Error: Neither mariadb-dump nor mysqldump could be found." >&2; return 1; fi
    echo "Using ${dump_command} for the backup."
    local backup_file="${private_directory}/database-backup-$(date +"%Y-%m-%d").sql"
    if ! "${dump_command}" -u"${database_username}" -p"${database_password}" --max_allowed_packet=512M --default-character-set=utf8mb4 --add-drop-table --single-transaction --quick --lock-tables=false "${database_name}" > "${backup_file}"; then echo "Error: Database dump failed." >&2; rm -f "${backup_file}"; return 1; fi
    chmod 600 "${backup_file}"; echo "✅ Database backup complete!"; echo "   Backup file located at: ${backup_file}"
}

# ----------------------------------------------------
#  Checks the size and contents of autoloaded options in the WordPress database.
# ----------------------------------------------------
function db_check_autoload() {
    echo "Checking autoloaded options in the database..."
    # Ensure the 'gum' utility is available for formatting
    if ! setup_gum; then
        echo "Aborting check: gum setup failed." >&2
        return 1
    fi
    if ! setup_wp_cli; then echo "Error: wp-cli is not installed." >&2; return 1; fi
    if ! "$WP_CLI_CMD" core is-installed --quiet; then echo "Error: This does not appear to be a WordPress installation." >&2; return 1; fi

    echo
    echo "--- Total Autoloaded Size ---"
    "$WP_CLI_CMD" db query "SELECT ROUND(SUM(LENGTH(option_value))/1024/1024, 2) as 'Autoload MB', COUNT(*) as 'Count' FROM $($WP_CLI_CMD db prefix)options WHERE autoload IN ('yes', 'on');" | "$GUM_CMD" table --print --separator $'\t'
    echo
    echo "--- Top 25 Autoloaded Options & Totals ---"
    "$WP_CLI_CMD" db query "SELECT option_name, round(length(option_value) / 1024 / 1024, 2) as 'Size (MB)' FROM $($WP_CLI_CMD db prefix)options WHERE autoload IN ('yes', 'on') ORDER BY length(option_value) DESC LIMIT 25" | "$GUM_CMD" table --print --separator $'\t'
    echo
    echo "✅ Autoload check complete."
}

# ----------------------------------------------------
#  Optimizes the database by converting tables to InnoDB, reporting large tables, and cleaning transients.
# ----------------------------------------------------
function db_optimize() {
    # --- Pre-flight checks ---
    if ! setup_gum; then
        echo "Aborting optimization: gum setup failed." >&2
        return 1
    fi
    if ! setup_wp_cli; then echo "Error: WP-CLI not found." >&2; return 1; fi
    if ! "$WP_CLI_CMD" core is-installed --quiet; then echo "Error: This does not appear to be a WordPress installation." >&2; return 1; fi

    echo "🚀 Starting database optimization..."
    echo ""

    # --- Step 1: Convert MyISAM to InnoDB ---
    echo "--- Step 1: Checking for MyISAM tables to convert to InnoDB ---"
    local myisam_tables
    myisam_tables=$("$WP_CLI_CMD" db query "SELECT TABLE_NAME FROM information_schema.TABLES WHERE ENGINE = 'MyISAM' AND TABLE_SCHEMA = DATABASE()" --skip-column-names)

    if [[ -z "$myisam_tables" ]]; then
        echo "✅ All tables are already using the InnoDB engine. No conversion needed."
    else
        echo "Found the following MyISAM tables to convert:"
        # Use gum to format the list of tables
        "$WP_CLI_CMD" db query "SELECT TABLE_NAME AS 'MyISAM Tables' FROM information_schema.TABLES WHERE ENGINE = 'MyISAM' AND TABLE_SCHEMA = DATABASE()" | "$GUM_CMD" table --print --separator $'\t'

        echo "Converting tables to InnoDB..."
        "$WP_CLI_CMD" db query "SELECT CONCAT('ALTER TABLE \`', TABLE_NAME, '\` ENGINE=InnoDB;') FROM information_schema.TABLES WHERE ENGINE = 'MyISAM' AND TABLE_SCHEMA = DATABASE()" --skip-column-names | "$WP_CLI_CMD" db query

        if [ $? -eq 0 ]; then
            echo "✅ Successfully converted tables to InnoDB."
        else
            echo "❌ An error occurred during the conversion."
            return 1
        fi
    fi

    # --- Step 2: List Top 10 Largest Tables ---
    echo ""
    echo "--- Step 2: Top 10 Tables Larger Than 1MB ---"
    # Use gum to format the table of large tables
    "$WP_CLI_CMD" db query "
      SELECT
        TABLE_NAME,
        CASE
          WHEN (data_length + index_length) >= 1073741824 THEN CONCAT(ROUND((data_length + index_length) / 1073741824, 2), ' GB')
          WHEN (data_length + index_length) >= 1048576 THEN CONCAT(ROUND((data_length + index_length) / 1048576, 2), ' MB')
          WHEN (data_length + index_length) >= 1024 THEN CONCAT(ROUND((data_length + index_length) / 1024, 2), ' KB')
          ELSE CONCAT((data_length + index_length), ' B')
        END AS Size
      FROM
        information_schema.TABLES
     WHERE
        TABLE_SCHEMA = DATABASE() AND (data_length + index_length) > 1048576
      ORDER BY
        (data_length + index_length) DESC
      LIMIT 10;
    " | "$GUM_CMD" table --print --separator $'\t'

    # --- Step 3: Delete Expired Transients ---
    echo ""
    echo "--- Step 3: Deleting Expired Transients ---"
    "$WP_CLI_CMD" transient delete --expired

    echo ""
    echo "✅ Database optimization complete."
}

# ----------------------------------------------------
#  Changes the database table prefix for a WordPress installation.
# ----------------------------------------------------
function db_change_prefix() {
    echo "🚀 Starting Database Prefix Change 🚀"

    # --- Pre-flight Checks ---
    if ! setup_wp_cli; then echo "❌ Error: WP-CLI not found." >&2; return 1; fi
    if ! "$WP_CLI_CMD" core is-installed --quiet; then echo "❌ Error: This does not appear to be a WordPress installation." >&2; return 1; fi
    if ! setup_gum; then echo "❌ Error: gum is required for interactive prompts." >&2; return 1; fi
    if ! command -v sed &>/dev/null; then echo "❌ Error: sed command not found." >&2; return 1; fi

    # --- Get Current and New Prefix ---
    local db_prefix
    db_prefix=$("$WP_CLI_CMD" db prefix)
    echo "Current database prefix is: $db_prefix"

    local random_string
    # Use a more portable random string generator to avoid locale issues.
    if command -v openssl &>/dev/null; then
        random_string=$(openssl rand -hex 3) # 6 hex characters
    elif command -v md5sum &>/dev/null; then
        random_string=$(date +%s | md5sum | head -c 5)
    elif command -v sha1sum &>/dev/null; then
        random_string=$(date +%s | sha1sum | head -c 5)
    else
        # A simpler fallback if no hashing tool is found
        random_string=$(date +%s | cut -c 6-10) # last 5 digits of timestamp
    fi
    local db_prefix_new
    db_prefix_new=$("$GUM_CMD" input --value="wp_${random_string}_" --prompt="Enter the new database prefix: ")

    if [ -z "$db_prefix_new" ]; then
        echo "❌ No new prefix entered. Aborting."
        return 1
    fi
    
    if [ "$db_prefix" == "$db_prefix_new" ]; then
        echo "❌ The new prefix is the same as the current prefix. Aborting."
        return 1
    fi

    echo "You are about to change the database prefix from '${db_prefix}' to '${db_prefix_new}'."
    "$GUM_CMD" confirm "This is a potentially destructive operation. Are you sure you want to continue?" || { echo "Operation cancelled."; return 0; }

    # --- Backup Database ---
    local private_dir
    if ! private_dir=$(_get_private_dir); then
        return 1
    fi
    local db_file="${private_dir}/prefix-change-backup-$(date +"%Y-%m-%d-%H%M%S").sql"
    echo "Step 1/5: Backing up database to a temporary file..."
    if ! "$WP_CLI_CMD" db export "$db_file" --add-drop-table; then
        echo "❌ Error: Failed to create database backup. Aborting."
        return 1
    fi
    echo "✅ Database backup created at: $db_file"

    # --- Modify SQL File ---
    echo "Step 2/5: Modifying the database backup with the new prefix..."
    # The -i flag for sed behaves differently on macOS/BSD vs Linux.
    # Providing a backup extension (e.g., -i.bak) makes it work on both.
    sed -i.bak "s#\`${db_prefix}#\`${db_prefix_new}#g" "$db_file"
    sed -i.bak "s#'${db_prefix}user_roles#'${db_prefix_new}user_roles#g" "$db_file"
    sed -i.bak "s#'${db_prefix}capabilities#'${db_prefix_new}capabilities#g" "$db_file"
    sed -i.bak "s#'${db_prefix}user_level#'${db_prefix_new}user_level#g" "$db_file"
    echo "✅ SQL file modified."

    # --- Reset and Import ---
    echo "Step 3/5: Resetting the database (dropping all tables)..."
    "$WP_CLI_CMD" db reset --yes

    echo "Step 4/5: Importing the modified database..."
    if ! "$WP_CLI_CMD" db import "$db_file"; then
        echo "❌ Error: Failed to import the modified database."
        echo "   Your original database is backed up at: $db_file"
        echo "   You may need to manually restore it."
        # Clean up the .bak file
        rm -f "${db_file}.bak"
        return 1
    fi
    echo "✅ Database imported successfully."
    # Clean up the .bak file created by sed
    rm -f "${db_file}.bak"

    # --- Update wp-config.php ---
    echo "Step 5/5: Updating wp-config.php with the new prefix..."
    if ! "$WP_CLI_CMD" config set table_prefix "$db_prefix_new" --skip-plugins --skip-themes; then
         echo "❌ Error: Failed to update the table_prefix in your wp-config.php file."
         echo "   Please update it manually to: \$table_prefix = '$db_prefix_new';"
         return 1
    fi
    echo "✅ wp-config.php updated."
    
    echo ""
    echo "✨ Database prefix change complete!"
    echo "   The backup file from before the change is still available at: $db_file"
}

# ----------------------------------------------------
#  Remotely installs the Disembark plugin, connects, and initiates a backup using an embedded Playwright script. 
# ----------------------------------------------------
function run_disembark() {
    local target_url_input="$1"
    local debug_flag="$2"

    echo "🚀 Starting Disembark process for ${target_url_input}..."

    # --- 1. Pre-flight Checks for disembark-cli ---
    if [ -z "$target_url_input" ];then
        echo "❌ Error: Missing required URL argument." >&2
        show_command_help "disembark"
        return 1
    fi

    if ! setup_disembark; then return 1; fi 

    # --- 2. Smart URL Parsing ---
    local base_url
    local login_path
    
    # Check if the input URL contains /wp-admin or /wp-login.php
    if [[ "$target_url_input" == *"/wp-admin"* || "$target_url_input" == *"/wp-login.php"* ]]; then
        # If it's a backend URL, extract the base and the path
        base_url=$(echo "$target_url_input" | sed -E 's#(https?://[^/]+).*#\1#')
        login_path=$(echo "$target_url_input" | sed -E "s#$base_url##")
        echo "   - Detected backend URL. Base: '$base_url', Path: '$login_path'"
    # Handle URLs with a path component that don't end in a slash (potential custom login)
    elif [[ "$target_url_input" == *"/"* && "${target_url_input: -1}" != "/" ]]; then
        local path_part
        # Use sed -n with 'p' to ensure it only outputs on a successful match
        path_part=$(echo "$target_url_input" | sed -n -E 's#https?://[^/]+(/.*)#\1#p')

        # If path_part is empty, it means there was no path after the domain (e.g., https://example.com)
        if [ -z "$path_part" ]; then
            base_url="${target_url_input%/}"
            login_path="/wp-login.php"
            echo "   - Homepage URL detected. Assuming default login path: '$login_path'"
        # Check for deep links inside WordPress content directories
        elif [[ "$path_part" == *"/wp-content"* || "$path_part" == *"/wp-includes"* ]]; then
            base_url="$target_url_input"
            login_path="/wp-login.php"
            echo "   - Deep link detected. Assuming default login for base URL."
        # Otherwise, assume it's a custom login path
        else
            base_url=$(echo "$target_url_input" | sed -E 's#(https?://[^/]+).*#\1#')
            login_path="$path_part"
            echo "   - Custom login path detected. Base: '$base_url', Path: '$login_path'"
        fi
    # Handle homepage URLs that might end with a slash
    else
        base_url="${target_url_input%/}" # Remove trailing slash if present
        login_path="/wp-login.php"
        echo "   - Homepage URL detected. Assuming default login path: '$login_path'"
    fi


    # --- 3. Attempt backup with a potentially stored token ---
    echo "✅ Attempting backup using a stored token..."
    if "$DISEMBARK_CMD" backup "$base_url"; then
        echo "✨ Backup successful using a pre-existing token." 
        return 0
    fi

    # --- 4. If backup fails, proceed to full browser authentication ---
    echo "⚠️ Backup with stored token failed. A new connection token is likely required." 
    echo "Proceeding with browser authentication..."

    # --- Pre-flight Checks for browser automation ---
    if ! setup_playwright; then return 1; fi 
    if ! setup_gum; then return 1; fi 

    # --- Define the Playwright script using a Heredoc ---
    local PLAYWRIGHT_SCRIPT
    PLAYWRIGHT_SCRIPT=$(cat <<'EOF'
// --- Embedded Playwright Script ---
const { chromium } = require('playwright');
const https = require('https');
const fs = require('fs');
const os = require('os');
const path = require('path');

const PLUGIN_ZIP_URL = 'https://github.com/DisembarkHost/disembark-connector/releases/latest/download/disembark-connector.zip';

async function main() {
  const [, , baseUrl, loginPath, username, password, debugFlag] = process.argv;

  if (!baseUrl || !loginPath || !username || !password) {
    console.error('Usage: node disembark-browser.js <baseUrl> <loginPath> <username> <password> [debug]');
    process.exit(1);
  }
  
  const loginUrl = baseUrl + loginPath;
  const adminUrl = baseUrl + '/wp-admin/';

  const isHeadless = debugFlag !== 'true';
  const browser = await chromium.launch({ headless: isHeadless });

  const context = await browser.newContext({
    userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36'
  });
  const page = await context.newPage();
  try {
    // 1. LOGIN
    process.stdout.write(`   - Step 1/5: Authenticating with WordPress at ${loginUrl}...`);
    await page.goto(loginUrl, { waitUntil: 'domcontentloaded' });
    
    if (!(await page.isVisible('#user_login'))) {
        console.log(' Failed.');
        console.error('LOGIN_URL_INVALID');
        process.exit(2);
    }

    await page.fill('#user_login', username);
    await page.fill('#user_pass', password);
    await page.click('#wp-submit');
    
    try {
        await page.waitForSelector('#wpadminbar, #login_error, #correct-admin-email', { timeout: 60000 });
    } catch (e) {
        throw new Error('Authentication timed out. The page did not load the admin bar, a login error, or the admin email confirmation screen.');
    }

    if (await page.isVisible('#login_error')) {
        const errorText = await page.locator('#login_error').textContent();
        console.error(`LOGIN_FAILED: ${errorText.trim()}`);
        process.exit(3);
    }

    if (await page.isVisible('#correct-admin-email')) {
        process.stdout.write(' Admin email confirmation required. Submitting...');
        await page.click('#correct-admin-email');
        await page.waitForSelector('#wpadminbar', { timeout: 60000 });
    }

    if (!(await page.isVisible('#wpadminbar'))) { 
      throw new Error('Authentication failed. Admin bar not found after login.');
    }

    // --- Recovery Step: Navigate to the main dashboard to bypass any welcome/update screens ---
    if (!page.url().startsWith(adminUrl)) {
        process.stdout.write(' Navigating to main dashboard to bypass intermediate pages...');
        await page.goto(adminUrl, { waitUntil: 'networkidle' });
        await page.waitForSelector('#wpadminbar'); // Re-confirm we are in the admin area
        process.stdout.write(' Done.');
    }

    console.log(' Success!');

    // 2. CHECK IF PLUGIN EXISTS & ACTIVATE IF NEEDED
    process.stdout.write('   - Step 2/5: Checking plugin status...');
    await page.goto(`${adminUrl}plugins.php`, { waitUntil: 'networkidle' }); 

    const pluginRow = page.locator('tr[data-slug="disembark-connector"]');
    if (await pluginRow.count() > 0) { 
      console.log(' Plugin found.');
      const activateLink = pluginRow.locator('a.edit:has-text("Activate")');
      if (await activateLink.count() > 0) { 
        process.stdout.write('   - Activating existing plugin...');
        await Promise.all([ 
          page.waitForNavigation({ waitUntil: 'networkidle' }),
          activateLink.click()
        ]);
        console.log(' Activated!'); 
      } else {
        console.log('   - Plugin already active.');
      }
    } else {
      // 3. UPLOAD AND INSTALL PLUGIN
      console.log(' Plugin not found, proceeding with installation.');
      process.stdout.write('   - Step 3/5: Downloading plugin...');
      const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'disembark-'));
      const pluginZipPath = path.join(tempDir, 'disembark-connector.zip');
      await new Promise((resolve, reject) => { 
        const file = fs.createWriteStream(pluginZipPath);
        const request = (url) => {
          https.get(url, (response) => {
            if (response.statusCode > 300 && response.statusCode < 400 && response.headers.location) {
              request(response.headers.location);
            } else { 
              response.pipe(file);
              file.on('finish', () => file.close(resolve));
            }
          }).on('error', (err) => {
            fs.unlinkSync(pluginZipPath);
            reject(err);
          });
        };
        request(PLUGIN_ZIP_URL); 
      });

      console.log(' Download complete.');
      process.stdout.write('   - Uploading and installing...');
      await page.goto(`${adminUrl}plugin-install.php?tab=upload`);
      await page.setInputFiles('input#pluginzip', pluginZipPath);
      await page.waitForSelector('input#install-plugin-submit:not([disabled])', { timeout: 10000 });

      await page.click('input#install-plugin-submit');
      
      const activationLinkSelector = 'a:has-text("Activate Plugin"), a.activate-now, .button.activate-now';
      const alreadyInstalledSelector = 'body:has-text("Destination folder already exists.")';
      const mixedSuccessSelector = 'body:has-text("Plugin installed successfully.")';
      const genericErrorSelector = '.wrap > .error, .wrap > #message.error';
      
      try {
        await page.waitForSelector(
          `${activationLinkSelector}, ${alreadyInstalledSelector}, ${mixedSuccessSelector}, ${genericErrorSelector}`,
          { timeout: 90000 }
        );
      } catch (e) {
        throw new Error('Timed out waiting for a response after clicking "Install Now".');
      }

      if (await page.locator(activationLinkSelector).count() > 0) {
        const activateButton = page.locator(activationLinkSelector);
        await Promise.all([
          page.waitForNavigation({ waitUntil: 'networkidle' }),
          activateButton.first().click(),
        ]);
        console.log(' Installed & Activated!');
      } else if (await page.locator(alreadyInstalledSelector).count() > 0) {
        console.log(' Plugin already installed.');
      } else if (await page.locator(mixedSuccessSelector).count() > 0) {
        console.log(' Install succeeded, but page reported an error. Navigating to plugins page to activate...');
        await page.goto(`${adminUrl}plugins.php`, { waitUntil: 'networkidle' });
        const pluginRow = page.locator('tr[data-slug="disembark-connector"]');
        const activateLink = pluginRow.locator('a.edit:has-text("Activate")');
        if (await activateLink.count() > 0) {
            await Promise.all([
              page.waitForNavigation({ waitUntil: 'networkidle' }),
              activateLink.click()
            ]);
            console.log(' Activated!');
        } else {
            console.log('   - Plugin was already active on the plugins page.');
        }
      } else {
        const errorText = await page.locator(genericErrorSelector).first().textContent();
        throw new Error(`Plugin installation failed with a WordPress error: ${errorText.trim()}`);
      }

      fs.unlinkSync(pluginZipPath);
      fs.rmdirSync(tempDir);
    }

    // 4. RETRIEVE TOKEN
    process.stdout.write('   - Step 4/5: Retrieving connection token...');
    const tokenPageUrl = `${adminUrl}plugin-install.php?tab=plugin-information&plugin=disembark-connector`; 
    await page.goto(tokenPageUrl, { waitUntil: 'networkidle' });

    const tokenElement = page.locator('div#section-description > code');
    if (await tokenElement.count() === 0) { 
      throw new Error('Could not find the connection token element on the page.');
    }
    const token = await tokenElement.first().textContent();
    console.log(' Token found!');
    // 5. OUTPUT TOKEN FOR BASH SCRIPT
    process.stdout.write('   - Step 5/5: Sending token back to script...');
    console.log(token.trim()); 
    
  } catch (error) {
    console.error(`\nError: ${error.message}`);
    process.exit(1);
  } finally {
    await browser.close();
  }
}

main();
EOF
)
    # --- Helper function for getting credentials ---
    _get_credentials() {
        echo "Please provide WordPress administrator credentials:"
        username=$("$GUM_CMD" input --placeholder="Enter WordPress username...")
        if [ -z "$username" ]; then
            echo "No username provided. Aborting." >&2
            return 1
        fi

        password=$("$GUM_CMD" input --placeholder="Enter WordPress password..." --password)
        if [ -z "$password" ]; then
            echo "No password provided. Aborting." >&2
            return 1
        fi
        return 0
    }

    # --- Helper for running playwright ---
    run_playwright_and_get_token() {
        local url_to_run="$1"
        local path_to_run="$2"
        local user_to_run="$3"
        local pass_to_run="$4"

        echo "🤖 Launching browser to automate login and plugin setup..."
        echo "   - Attempting login at: ${url_to_run}${path_to_run}"

        set -o pipefail
        local full_output
        full_output=$(echo "$PLAYWRIGHT_SCRIPT" | node - "$url_to_run" "$path_to_run" "$user_to_run" "$pass_to_run" "$debug_flag" | tee /dev/tty)
        local exit_code=$?
        set +o pipefail

        if [ $exit_code -eq 3 ]; then
            return 3 # Bad credentials
        elif [ $exit_code -eq 2 ]; then
            return 2 # Invalid URL
        elif [ $exit_code -ne 0 ]; then
            return 1 # General failure
        fi
        
        echo "$full_output" | tail -n 1 | tr -d '[:space:]'
        return 0
    }

    # --- Authentication Loop ---
    local token
    local playwright_exit_code
    
    # Initial credential prompt
    if ! _get_credentials; then return 1; fi

    while true; do
        token=$(run_playwright_and_get_token "$base_url" "$login_path" "$username" "$password")
        playwright_exit_code=$?

        if [ $playwright_exit_code -eq 0 ]; then
            break # Success
        elif [ $playwright_exit_code -eq 2 ]; then # Invalid URL
            echo "⚠️ The login URL '${base_url}${login_path}' appears to be incorrect."
            local new_login_url
            new_login_url=$("$GUM_CMD" input --placeholder="Enter the full, correct WordPress Admin URL...")

            if [ -z "$new_login_url" ]; then
                echo "No URL provided. Aborting." >&2; return 1;
            fi
            base_url=$(echo "$new_login_url" | sed -E 's#(https?://[^/]+).*#\1#')
            login_path=$(echo "$new_login_url" | sed -E "s#$base_url##")
            continue # Retry loop with new URL
        elif [ $playwright_exit_code -eq 3 ]; then # Bad credentials
            echo "⚠️ Login failed. The credentials may be incorrect."
            if "$GUM_CMD" confirm "Re-enter credentials and try again?"; then
                if ! _get_credentials; then return 1; fi
                continue # Retry loop with new credentials
            else
                echo "Authentication cancelled." >&2; return 1;
            fi
        else # General failure
            echo "❌ Browser automation failed. Please check errors above." >&2
            return 1
        fi
    done

    # --- Final Check and Backup ---
    if [ $playwright_exit_code -ne 0 ] || [ -z "$token" ]; then
        echo "❌ Could not retrieve a token. Aborting." >&2
        return 1
    fi

    echo "✅ Browser automation successful. Token retrieved."
    echo "📞 Connecting and starting backup with disembark-cli..."
    if ! "$DISEMBARK_CMD" connect "${base_url}" "${token}"; then
        echo "❌ Error: Failed to connect using the retrieved token." >&2
        return 1
    fi
    
    if ! "$DISEMBARK_CMD" backup "${base_url}"; then
        echo "❌ Error: Backup command failed after connecting." >&2
        return 1
    fi

    echo "✨ Disembark process complete!" 
}
# ----------------------------------------------------
#  Dumps the content of files matching a pattern into a single text file.
# ----------------------------------------------------
function run_dump() {
    # --- 1. Validate Input ---
    local INPUT_PATTERN="$1"
    shift
    local exclude_patterns=("$@")

    if [ -z "$INPUT_PATTERN" ];
    then
        echo "Error: No input pattern provided." >&2
        echo "Usage: _do dump \"<path/to/folder/*.extension>\" [-x <exclude_pattern>]..." >&2
        return 1
    fi

    # --- 2. Determine Paths and Names ---
    local SEARCH_DIR
    SEARCH_DIR=$(dirname "$INPUT_PATTERN")
    local FILE_PATTERN
    FILE_PATTERN=$(basename "$INPUT_PATTERN")

    local OUTPUT_BASENAME
    OUTPUT_BASENAME=$(basename "$SEARCH_DIR")
    local OUTPUT_FILE
    if [ "$OUTPUT_BASENAME" == "." ]; then
        # If searching in the current dir, use the folder's name for the output file.
        OUTPUT_BASENAME=$(basename "$(pwd)")
        OUTPUT_FILE="${OUTPUT_BASENAME}-dump.txt"
    else
        OUTPUT_FILE="${OUTPUT_BASENAME}.txt"
    fi

    # --- 3. Process Files ---
    > "$OUTPUT_FILE"

    echo "Searching in '$SEARCH_DIR' for files matching '$FILE_PATTERN'..."
    if [ ${#exclude_patterns[@]} -gt 0 ]; then
        echo "Excluding user-defined patterns: ${exclude_patterns[*]}"
    fi
    echo "Automatically excluding: .git directory contents"

    # Dynamically build the find command
    local find_cmd=("find" "$SEARCH_DIR" "-type" "f" "-name" "$FILE_PATTERN")

    # Add user-defined exclusions
    for pattern in "${exclude_patterns[@]}"; do
        if [[ "$pattern" == */ ]]; then
            # For directories (pattern ends with /), use -path
            local dir_pattern=${pattern%/} # remove trailing slash
            find_cmd+=("-not" "-path" "*/$dir_pattern/*")
        else
            # For files, use -name
            find_cmd+=("-not" "-name" "$pattern")
        fi
    done

    # Add automatic exclusions for the output file and .git directory
    find_cmd+=("-not" "-name" "$OUTPUT_FILE")
    find_cmd+=("-not" "-path" "*/.git/*")

    # Execute the find command
    "${find_cmd[@]}" -print0 | while IFS= read -r -d '' file; do
        echo "--- File: $file ---" >> "$OUTPUT_FILE"
        cat "$file" >> "$OUTPUT_FILE"
        echo -e "\n" >> "$OUTPUT_FILE"
    done

    # --- 4. Final Report ---
    if [ ! -s "$OUTPUT_FILE" ]; then
        echo "Warning: No files found matching the pattern. No dump file created."
        rm "$OUTPUT_FILE"
        return 0
    fi

    local FILE_SIZE
    FILE_SIZE=$(du -h "$OUTPUT_FILE" | cut -f1 | xargs)

    # --- WordPress URL Logic ---
    local dump_url=""
    # Silently check if WP-CLI is available and we're in a WordPress installation.
    if setup_wp_cli &>/dev/null && "$WP_CLI_CMD" core is-installed --quiet 2>/dev/null; then
        local wp_home
        wp_home=$("$WP_CLI_CMD" option get home --skip-plugins --skip-themes 2>/dev/null)
        
        # We need `realpath` for this to work reliably
        if [ -n "$wp_home" ] && command -v realpath &>/dev/null; then
            local wp_root_path
            # Use `wp config path` to get the wp-config.php path, which is more reliable.
            wp_root_path=$("$WP_CLI_CMD" config path --quiet 2>/dev/null)
            
            # Only proceed if we found a valid wp-config.php path.
            if [ -n "$wp_root_path" ] && [ -f "$wp_root_path" ]; then
                wp_root_path=$(dirname "$wp_root_path")
                
                local current_path
                current_path=$(realpath ".")
                
                # Get the path of the current directory relative to the WordPress root
                local relative_path
                relative_path=${current_path#"$wp_root_path"}
                
                # Construct the final URL
                # This ensures no double slashes and correctly handles the root directory case
                dump_url="${wp_home%/}${relative_path}/${OUTPUT_FILE}"
            fi
        fi
    fi
    # --- End WordPress URL Logic ---

    echo "Generated $OUTPUT_FILE ($FILE_SIZE)"
    if [ -n "$dump_url" ]; then
        echo "URL: $dump_url"
    fi
}
# ----------------------------------------------------
#  Sends an email using wp_mail.
# ----------------------------------------------------
function run_email() {
    echo "🚀 Preparing to send an email via WP-CLI..."

    # --- Pre-flight Checks ---
    if ! setup_wp_cli; then echo "❌ Error: WP-CLI not found." >&2; return 1; fi
    if ! "$WP_CLI_CMD" core is-installed --quiet; then echo "❌ Error: This does not appear to be a WordPress installation." >&2; return 1; fi
    if ! setup_gum; then echo "Aborting: gum setup failed." >&2; return 1; fi

    # --- Gather Email Details with Gum ---
    local to_email
    to_email=$("$GUM_CMD" input --placeholder="Recipient email address...")
    if [ -z "$to_email" ]; then echo "❌ No email address provided. Aborting."; return 1; fi

    local subject
    subject=$("$GUM_CMD" input --placeholder="Email subject...")
    if [ -z "$subject" ]; then echo "❌ No subject provided. Aborting."; return 1; fi

    local content
    echo "Enter email content (press Ctrl+D when finished):"
    content=$("$GUM_CMD" write)
    if [ -z "$content" ]; then echo "❌ No content provided. Aborting."; return 1; fi

    # --- Construct and Execute Command ---
    echo "Sending email..."

    # Escape single quotes in the variables to prevent breaking the wp eval command
    local escaped_to_email; escaped_to_email=$(printf "%s" "$to_email" | sed "s/'/\\\'/g")
    local escaped_subject; escaped_subject=$(printf "%s" "$subject" | sed "s/'/\\\'/g")
    local escaped_content; escaped_content=$(printf "%s" "$content" | sed "s/'/\\\'/g")

    local wp_command="wp_mail( '$escaped_to_email', '$escaped_subject', '$escaped_content', ['Content-Type: text/html; charset=UTF-8'] );"

    # Use a temporary variable to capture the output from wp eval
    local eval_output
    eval_output=$("$WP_CLI_CMD" eval "$wp_command" 2>&1)
    local exit_code=$?

    # The `wp_mail` function in WordPress returns `true` on success and `false` on failure.
    # However, `wp eval` doesn't directly translate this boolean to an exit code.
    # We can check the output. A successful `wp_mail` call via `wp eval` usually produces no output.
    # A failure might produce a PHP error or warning.
    if [ $exit_code -eq 0 ]; then
        echo "✅ Email command sent successfully to $to_email."
        echo "   Please check the recipient's inbox and the mail server logs to confirm delivery."
    else
        echo "❌ Error: The 'wp eval' command failed. Please check your WordPress email configuration."
        echo "   WP-CLI output:"
        echo "$eval_output"
        return 1
    fi
}

# ----------------------------------------------------
#  Finds files that have been recently modified.
# ----------------------------------------------------
function find_recent_files() {
    local days="${1:-1}" # Default to 1 day if no argument is provided

    # Validate that the input is a number
    if ! [[ "$days" =~ ^[0-9]+$ ]]; then
        echo "❌ Error: Please provide a valid number of days." >&2
        echo "Usage: _do find recent-files <days>" >&2
        return 1
    fi

    echo "🔎 Searching for files modified in the last $days day(s)..."
    echo

    # Check the operating system to use the correct `find` command syntax.
    # The `-printf` option is not available on macOS/BSD `find`.
    if [[ "$(uname)" == "Darwin" ]]; then
        # On macOS, use -exec with `stat` for formatted, sortable output.
        # -f "%Sm %N" formats the output: Modification time, then file name.
        # -t "%Y-%m-%d %H:%M:%S" specifies the timestamp format for sorting.
        find . -type f -mtime "-${days}" -exec stat -f "%Sm %N" -t "%Y-%m-%d %H:%M:%S" {} + | sort -r
    else
        # On Linux, the more efficient -printf option is available.
        find . -type f -mtime "-${days}" -printf "%TY-%Tm-%Td %TH:%M:%S %p\n" | sort -r
    fi

    if [ $? -ne 0 ]; then
        echo "❌ Error: The 'find' command failed to execute." >&2
        return 1
    fi
}

# ----------------------------------------------------
#  Identifies plugins that may be slowing down WP-CLI command execution.
# ----------------------------------------------------
function find_slow_plugins() {
    local page_to_check="${1}"

    _get_wp_execution_time() {
        local output
        output=$("$WP_CLI_CMD" "$@" --debug 2>&1)
        echo "$output" | perl -ne '/Debug \(bootstrap\): Running command: .+\(([^s]+s)/ && print $1'
    }
    if ! setup_wp_cli; then echo "❌ Error: WP-CLI (wp command) not found." >&2; return 1; fi
    if ! "$WP_CLI_CMD" core is-installed --quiet; then echo "❌ Error: This does not appear to be a WordPress installation." >&2; return 1; fi

    local base_command_args=("plugin" "list")
    local skip_argument="--skip-plugins"
    local description="wp plugin list --debug"

    if [ -n "$page_to_check" ]; then
        echo "🚀 WordPress Plugin Performance Test for page: '$page_to_check' 🚀"
        description="wp render \"$page_to_check\" --debug"

        # Check for wp render and install if missing
        if ! "$WP_CLI_CMD" help render &> /dev/null; then
            echo "ℹ️ 'wp render' command not found. Installing 'render-command' plugin..."
            if ! "$WP_CLI_CMD" plugin install https://github.com/austinginder/render-command/releases/latest/download/render-command.zip --activate --force; then
                echo "❌ Error: Failed to install 'render-command' plugin. Aborting." >&2
                return 1
            fi
            echo "✅ 'render-command' plugin installed successfully."
        fi
        
        # Update command variables to use 'wp render'
        base_command_args=("render" "$page_to_check")
        skip_argument="--without-plugin"
    else
        echo "🚀 WordPress Plugin Performance Test 🚀"
    fi
    
    echo "This script measures the execution time of '$description' under various conditions."
    echo ""
    echo "📋 Initial Baseline Measurements for '$description':"

    local base_time_s
    printf "  ⏳ Measuring base time (ALL plugins & theme active)... "
    base_time_s=$(_get_wp_execution_time "${base_command_args[@]}")
    if [[ -z "$base_time_s" ]]; then
        echo "❌ Error: Could not measure base execution time." >&2
        return 1
    fi
    echo "Base time: $base_time_s"
    echo ""

    local active_plugins=()
    while IFS= read -r line; do
        active_plugins+=("$line")
    done < <("$WP_CLI_CMD" plugin list --field=name --status=active)

    if [[ ${#active_plugins[@]} -eq 0 ]]; then
        echo "ℹ️ No active plugins found to test."
        return 0
    fi

    echo "📊 Measuring impact of individual plugins (compared to '${base_time_s}' base time):"
    echo "A larger positive 'Impact' suggests the plugin contributes more to the load time of this specific WP-CLI command."
    echo "---------------------------------------------------------------------------------"
    printf "%-40s | %-15s | %-15s\n" "Plugin Skipped" "Time w/ Skip" "Impact (Base-Skip)"
    echo "---------------------------------------------------------------------------------"
    local results=()
    for plugin in "${active_plugins[@]}"; do
        # Skip the render-command plugin itself when using the render method
        if [[ -n "$page_to_check" && "$plugin" == "render-command" ]]; then
            continue
        fi

        local time_with_skip_s
        time_with_skip_s=$(_get_wp_execution_time "${base_command_args[@]}" "${skip_argument}=$plugin")

        if [[ -n "$time_with_skip_s" ]]; then
            local diff_s
            diff_s=$(awk -v base="${base_time_s%s}" -v skip="${time_with_skip_s%s}" 'BEGIN { printf "%.3f", base - skip }')
            local impact_sign=""
            if [[ $(awk -v diff="$diff_s" 'BEGIN { print (diff > 0) }') -eq 1 ]]; then
                impact_sign="+"
            fi
            results+=("$(printf "%.3f" "$diff_s")|$plugin|$time_with_skip_s|${impact_sign}${diff_s}s")
        else
            results+=("0.000|$plugin|Error|Error measuring")
        fi
    done

    local sorted_results=()
    while IFS= read -r line; do
        sorted_results+=("$line")
    done < <(printf "%s\n" "${results[@]}" | sort -t'|' -k1,1nr)

    for result_line in "${sorted_results[@]}"; do
        local p_name
        p_name=$(echo "$result_line" | cut -d'|' -f2)
        local t_skip
        t_skip=$(echo "$result_line" | cut -d'|' -f3)
        local i_str
        i_str=$(echo "$result_line" | cut -d'|' -f4)
        printf "%-40s | %-15s | %-15s\n" "$p_name" "$t_skip" "$i_str"
    done
    echo "---------------------------------------------------------------------------------"
    echo ""
    echo "✅ Test Complete"
    echo "💡 Note: This measures impact on a specific WP-CLI command. For front-end or"
    echo "   admin profiling, consider using a plugin like Query Monitor or New Relic."
    echo ""
}

# ----------------------------------------------------
#  Detects plugins that are active but hidden from the standard plugin list.
# ----------------------------------------------------
function find_hidden_plugins() {
    # --- Pre-flight Checks ---
    if ! setup_wp_cli; then echo "❌ Error: WP-CLI not found." >&2; return 1; fi
    if ! "$WP_CLI_CMD" core is-installed --quiet; then echo "❌ Error: This does not appear to be a WordPress installation." >&2; return 1; fi
    if ! setup_gum; then return 1; fi

    echo "🚀 Checking for hidden WordPress plugins..."

    # Get the standard list of active plugins
    local active_plugins
    active_plugins=$("$WP_CLI_CMD" plugin list --field=name --status=active)

    # Get the "raw" list of active plugins by skipping themes and other plugins
    local active_plugins_raw
    active_plugins_raw=$("$WP_CLI_CMD" plugin list --field=name --status=active --skip-themes --skip-plugins)

    local regular_count
    regular_count=$(echo "$active_plugins" | wc -l | xargs)
    local raw_count
    raw_count=$(echo "$active_plugins_raw" | wc -l | xargs)

    
    # Compare the counts of the two lists.
    if [[ "$regular_count" == "$raw_count" ]]; then
        echo "✅ No hidden plugins detected. The standard and raw plugin lists match ($regular_count plugins)."
        return 0
    fi

    # If the counts differ, find the plugins that are in the raw list but not the standard one.
    echo "⚠️ Found a discrepancy between plugin lists!"
    echo "   - Standard list shows: $regular_count active plugins."
    echo "   - Raw list shows: $raw_count active plugins."
    echo

    # Use 'comm' to find lines unique to the raw list.
    local hidden_plugins
    hidden_plugins=$(comm -13 <(echo "$active_plugins" | sort) <(echo "$active_plugins_raw" | sort))

    if [ -z "$hidden_plugins" ]; then
        echo "ℹ️  Could not isolate the specific hidden plugins, but a discrepancy exists."
    else
        echo "--- Found Hidden Plugin(s) ---"
        # Loop through each hidden plugin and get its details
        while IFS= read -r plugin; do
            if [ -z "$plugin" ]; then continue; fi

            "$GUM_CMD" log --level warn "Details for: $plugin"
            
            # Get plugin details in CSV format and pipe to gum for a clean table printout.
            "$WP_CLI_CMD" plugin get "$plugin" --skip-plugins --skip-themes --format=csv | \
                "$GUM_CMD" table --separator "," --widths=15,0 --print
            
            echo
        done <<< "$hidden_plugins"
        echo "💡 These plugins are active but may be hidden from the admin view or standard WP-CLI list."
        echo "   Common offenders are management plugins (like ManageWP's 'worker') or potentially malicious code."
    fi
}

# ----------------------------------------------------
#  Scans for potential malware and verifies WordPress core/plugin integrity.
# ----------------------------------------------------
function find_malware() {
    # --- Pre-flight Checks ---
    if ! setup_wp_cli; then echo "❌ Error: WP-CLI not found." >&2; return 1; fi
    if ! "$WP_CLI_CMD" core is-installed --quiet; then echo "❌ Error: This does not appear to be a WordPress installation." >&2; return 1; fi
    if ! command -v grep &> /dev/null; then echo "❌ Error: 'grep' command not found." >&2; return 1; fi
    if ! setup_gum; then return 1; fi

    echo "🚀 Starting malware scan..."
    echo "This process will check for suspicious code patterns and verify core/plugin file integrity."
    echo

    # --- 1. Hunt for suspicious PHP code ---
    echo "--- Step 1/3: Searching for suspicious PHP code patterns... ---"
    local suspicious_patterns=(
        'eval(base64_decode('
        'eval(gzinflate('
        'eval(gzuncompress('
        'eval(str_rot13('
        'preg_replace.*\/e'
        'create_function'
        'FilesMan'
        'c99shell'
        'r57shell'
        'shell_exec('
        'passthru('
        'system('
        'phpinfo('
        'assert('
    )

    local found_suspicious_files=false
    local combined_pattern
    combined_pattern=$(IFS='|'; echo "${suspicious_patterns[*]}")
    local search_results
    search_results=$(grep -rn --include='*.php' -iE "$combined_pattern" . 2>/dev/null)

    if [ -n "$search_results" ]; then
        echo "⚠️ Found potentially malicious code in the following files:"
        echo "-----------------------------------------------------"
        echo "$search_results"
        echo "-----------------------------------------------------"
        echo "💡 Review these files carefully. They may contain legitimate code that matches these patterns."
        found_suspicious_files=true
    else
        echo "✅ No suspicious code patterns found."
    fi
    echo

     # --- 2. Verify WordPress Core Checksums ---
    echo "--- Step 2/3: Verifying WordPress core file integrity... ---"
    if ! "$WP_CLI_CMD" core verify-checksums --skip-plugins --skip-themes; then
        echo "⚠️ WordPress core verification failed. The files listed above may have been modified."
    else
        echo "✅ WordPress core files verified successfully."
    fi
    echo

    # --- 3. Verify Plugin Checksums ---
    echo "--- Step 3/3: Verifying plugin file integrity (from wordpress.org)... ---"
    local stderr_file_plugin
    stderr_file_plugin=$(mktemp)

    local plugin_csv_data
    plugin_csv_data=$("$WP_CLI_CMD" plugin verify-checksums --all --format=csv --skip-plugins --skip-themes --quiet 2> "$stderr_file_plugin")
    local plugin_checksum_status=$?
    
    local plugin_summary_error
    plugin_summary_error=$(cat "$stderr_file_plugin")
    rm "$stderr_file_plugin"

    if [ $plugin_checksum_status -ne 0 ]; then
        echo "⚠️ Plugin verification encountered an error or found mismatches."

        # Check if there is any CSV data to display
        if [[ -n "$plugin_csv_data" ]]; then
            echo "$plugin_csv_data" | "$GUM_CMD" table --separator "," --print
        fi
        
        # Display the summary error if it exists
        if [ -n "$plugin_summary_error" ]; then
            echo "$plugin_summary_error"
        fi
        echo "💡 This may include plugins not in the wordpress.org directory (premium plugins) or modified files."
    else
        echo "✅ All plugins from wordpress.org verified successfully."
    fi
    echo

    echo "✅ Malware scan complete."
}

# ----------------------------------------------------
#  Finds outdated or invalid PHP opening tags in PHP files.
# ----------------------------------------------------
function find_outdated_php_tags() {
    local search_dir="${1:-.}"

    #  Ensure the search directory ends with a slash for consistency
    if [[ "${search_dir: -1}" != "/" ]]; then
        search_dir+="/"
    fi

    if [ ! -d "$search_dir" ]; then
        echo "❌ Error: Directory '$search_dir' not found." >&2
        return 1
    fi

    echo "🚀 Searching for outdated PHP tags in '${search_dir}'..."
    echo "This can take a moment for large directories."
    echo

    # This new, more portable method first finds all lines with '<?',
    # then filters out the lines containing valid tags like '<?php', '<?=', or '<?xml'.
    # This avoids reliance on potentially unsupported 'grep -P' features.
    local initial_results
    initial_results=$(grep --include="*.php" --line-number --recursive '<?' "$search_dir" 2>/dev/null \
        | grep -v -F -e '<?php' -e '<?=' -e '<?xml' \
        | grep --color=always -e '<?' -e '$^'
    )

    # Filter out common false positives from comments, strings, etc.
    local found_tags
    found_tags=$(echo "$initial_results" \
        | grep -v -F -e "strpos(" -e "str_replace(" \
        | grep -v -E "^[^:]*:[^:]*:\s*(\*|//|#)|'\<\?'|\"\<\?\"" \
    )

    if [ -z "$found_tags" ]; then
        echo "✅ No outdated PHP tags were found (after filtering common false positives)."
    else
        echo "⚠️ Found potentially outdated PHP tags in the following files:"
        echo "-----------------------------------------------------"
        #  The output from grep is already well-formatted.
        echo "$found_tags"
        echo "-----------------------------------------------------"
        #  Use single quotes instead of backticks to prevent command execution.
        echo "Recommendation: Replace all short tags like '<?' with the full '<?php' tag."
    fi
}
# ----------------------------------------------------
#  Applies HTTPS to a WordPress site's URLs.
# ----------------------------------------------------
function run_https() {
    echo "🚀 Applying HTTPS to site URLs..."

    # --- Pre-flight Checks ---
    if ! setup_wp_cli; then echo "❌ Error: WP-CLI not found." >&2; return 1; fi
    if ! "$WP_CLI_CMD" core is-installed --quiet; then echo "❌ Error: This does not appear to be a WordPress installation." >&2; return 1; fi
    if ! setup_gum; then echo "❌ Error: gum is required for interactive prompts." >&2; return 1; fi

    # --- Get Base Domain ---
    # Strips http/https and www to get a clean domain name.
    local domain
    domain=$("$WP_CLI_CMD" option get home)
    domain=${domain/http:\/\/www./}
    domain=${domain/https:\/\/www./}
    domain=${domain/http:\/\//}
    domain=${domain/https:\/\//}
    # Trim whitespace just in case
    domain=$( echo "$domain" | awk '{$1=$1};1' )

    # --- Ask User Preference for 'www' ---
    local use_www=false
    # Ask the user, with "No" as the default option.
    # If they select "Yes" (exit code 0), then set use_www to true.
    if "$GUM_CMD" confirm "Should the new HTTPS URL include 'www.'?" --default=false; then
        use_www=true
    fi

    # --- Define Target URLs ---
    local new_url
    local new_url_escaped
    if [ "$use_www" = true ]; then
        new_url="https://www.$domain"
        new_url_escaped="https:\/\/www.$domain"
    else
        new_url="https://$domain"
        new_url_escaped="https:\/\/$domain"
    fi

    echo "This will update all URLs to use '$new_url'."
    "$GUM_CMD" confirm "Proceed with search and replace?" || { echo "Operation cancelled by user."; return 0; }

    # --- Run Replacements ---
    echo "1/4: Replacing http://$domain ..."
    "$WP_CLI_CMD" search-replace "http://$domain" "$new_url" --all-tables --skip-plugins --skip-themes --report-changed-only

    echo "2/4: Replacing http://www.$domain ..."
    "$WP_CLI_CMD" search-replace "http://www.$domain" "$new_url" --all-tables --skip-plugins --skip-themes --report-changed-only

    echo "3/4: Replacing escaped http:\/\/$domain ..."
    "$WP_CLI_CMD" search-replace "http:\/\/$domain" "$new_url_escaped" --all-tables --skip-plugins --skip-themes --report-changed-only

    echo "4/4: Replacing escaped http:\/\/www.$domain ..."
    "$WP_CLI_CMD" search-replace "http:\/\/www.$domain" "$new_url_escaped" --all-tables --skip-plugins --skip-themes --report-changed-only

    echo "Flushing WordPress cache..."
    "$WP_CLI_CMD" cache flush

    echo ""
    echo "✅ HTTPS migration complete! All URLs updated to '$new_url'."
}

# ----------------------------------------------------
#  Installs helper and premium plugins.
# ----------------------------------------------------

# ----------------------------------------------------
#  Installs the Kinsta Must-Use plugin.
# ----------------------------------------------------
function install_kinsta_mu() {
    local force_flag="$1"

    # Check if this is a Kinsta environment unless --force is used
    if [[ "$force_flag" != "true" ]]; then
        if [ ! -f "/etc/update-motd.d/00-kinsta-welcome" ]; then
            echo "ℹ️ This does not appear to be a Kinsta environment. Skipping installation." >&2
            echo "   Use the --force flag to install anyway." >&2
            return 0
        fi
    else
        echo "✅ --force flag detected. Skipping Kinsta environment check."
    fi

    echo "🚀 Installing Kinsta MU plugin..."

    # --- Pre-flight Checks ---
    if ! setup_wp_cli; then echo "❌ Error: WP-CLI not found." >&2; return 1; fi
    if ! "$WP_CLI_CMD" core is-installed --quiet; then echo "❌ Error: This does not appear to be a WordPress installation." >&2; return 1; fi
    if ! command -v wget &>/dev/null; then echo "❌ Error: wget not found." >&2; return 1; fi
    if ! command -v unzip &>/dev/null; then echo "❌ Error: unzip not found." >&2; return 1; fi

    # Get wp-content path dynamically for reliability
    local wp_content_dir
    wp_content_dir=$("$WP_CLI_CMD" eval "echo rtrim(WP_CONTENT_DIR, '/');" --skip-plugins --skip-themes 2>/dev/null)
    if [ -z "$wp_content_dir" ] || [ ! -d "$wp_content_dir" ]; then
        echo "❌ Error: Could not determine wp-content directory." >&2
        return 1
    fi
    
    local mu_plugins_dir="${wp_content_dir}/mu-plugins"
    if [ ! -d "$mu_plugins_dir" ]; then
        echo "Creating directory: $mu_plugins_dir"
        mkdir -p "$mu_plugins_dir"
    fi

    # --- Installation ---
    local kinsta_zip_file="kinsta-mu-plugins.zip"
    
    # Download to the private directory to avoid clutter
    local private_dir
    if ! private_dir=$(_get_private_dir); then
        return 1
    fi
    local temp_zip_path="${private_dir}/${kinsta_zip_file}"

    if wget -q https://kinsta.com/kinsta-tools/kinsta-mu-plugins.zip -O "$temp_zip_path"; then
        unzip -o -q "$temp_zip_path" -d "$mu_plugins_dir/"
        rm "$temp_zip_path"
        echo "✅ Kinsta MU plugin installed successfully to ${mu_plugins_dir}/."
    else
        echo "❌ Error: Could not download the Kinsta MU plugin."
        # Clean up failed download
        [ -f "$temp_zip_path" ] && rm "$temp_zip_path"
        return 1
    fi
}

# ----------------------------------------------------
#  Installs the CaptainCore Helper plugin.
# ----------------------------------------------------
function install_helper() {
    echo "🚀 Deploying CaptainCore Helper..."

    # --- Pre-flight Checks ---
    if ! command -v curl &>/dev/null; then echo "❌ Error: curl not found." >&2; return 1; fi

    # --- Deployment ---
    if curl -sSL https://run.captaincore.io/deploy-helper | bash -s; then
        echo "✅ CaptainCore Helper deployed successfully."
    else
        echo "❌ Error: Failed to deploy CaptainCore Helper."
        return 1
    fi
}

# ----------------------------------------------------
#  Installs The Events Calendar Pro.
# ----------------------------------------------------
function install_events_calendar_pro() {
    echo "🚀 Installing The Events Calendar Pro..."

    # --- Pre-flight Checks ---
    if ! setup_wp_cli; then echo "❌ Error: WP-CLI not found." >&2; return 1; fi
    if ! "$WP_CLI_CMD" core is-installed --quiet; then echo "❌ Error: This does not appear to be a WordPress installation." >&2; return 1; fi
    if ! setup_gum; then echo "Aborting: gum setup failed." >&2; return 1; fi
    
    # --- Get License Key ---
    local license_key
    license_key=$("$GUM_CMD" input --placeholder="Enter Events Calendar Pro license key..." --password)

    if [ -z "$license_key" ]; then
        echo "❌ No license key provided. Aborting installation." >&2
        return 1
    fi

    # --- Installation Steps ---
    echo "Step 1/3: Installing 'The Events Calendar' (free version)..."
    if ! "$WP_CLI_CMD" plugin install the-events-calendar --force --activate; then
        echo "❌ Error: Failed to install the free version of The Events Calendar." >&2
        return 1
    fi

    echo "Step 2/3: Saving license key..."
    if ! "$WP_CLI_CMD" option update pue_install_key_events_calendar_pro "$license_key"; then
        echo "❌ Error: Failed to save the license key to the database." >&2
        return 1
    fi

    echo "Step 3/3: Installing 'Events Calendar Pro'..."
    local pro_plugin_url="https://pue.tri.be/api/plugins/v2/download?plugin=events-calendar-pro&key=$license_key"
    if ! "$WP_CLI_CMD" plugin install "$pro_plugin_url" --force --activate; then
        echo "❌ Error: Failed to install Events Calendar Pro. Please check your license key." >&2
        return 1
    fi

    echo "✅ The Events Calendar Pro installed and activated successfully."
}
# ----------------------------------------------------
#  Launches site - updates url from dev to live,
#  enables search engine visibility, and clears cache.
# ----------------------------------------------------
function run_launch() {
    # The domain is passed as the first argument, skip_confirm as the second
    local domain="$1"
    local skip_confirm="$2"

    echo "🚀 Launching Site"

    # --- Pre-flight Checks ---
    if ! setup_wp_cli; then echo "❌ Error: WP-CLI not found." >&2; return 1; fi
    if ! "$WP_CLI_CMD" core is-installed --quiet; then echo "❌ Error: This does not appear to be a WordPress installation." >&2; return 1; fi
    if ! setup_gum; then echo "❌ Error: gum is required for interactive prompts." >&2; return 1; fi

    # --- Get New Domain ---
    if [ -z "$domain" ]; then
        # If no argument is passed, prompt interactively
        domain=$("$GUM_CMD" input --placeholder "Enter the new live domain (e.g., example.com)...")
    else
        # If an argument is passed, just confirm the value
        echo "Using provided domain: $domain"
    fi

    if [ -z "$domain" ]; then
        echo "No domain entered. Launch cancelled."
        return 1
    fi

    # --- Get Current Domain ---
    local current_domain
    current_domain=$("$WP_CLI_CMD" option get home --skip-plugins --skip-themes)
    # Strip protocols
    current_domain=${current_domain/http:\/\//}
    current_domain=${current_domain/https:\/\//}
    # Trim whitespace
    current_domain=$(echo "$current_domain" | awk '{$1=$1};1')

    if [[ -z "$current_domain" ]] || [[ "$current_domain" != *"."* ]]; then
        echo "❌ Error: Could not find a valid existing domain from the WordPress installation." >&2
        return 1
    fi

    if [[ "$current_domain" == "$domain" ]]; then
        echo "The new domain is the same as the current domain. No changes needed."
        return 0
    fi

    # --- Confirmation ---
    # Only ask for confirmation if the skip_confirm flag is not true
    if [[ "$skip_confirm" != "true" ]]; then
        echo "This will update the site URL from '$current_domain' to '$domain'."
        "$GUM_CMD" confirm "Proceed with launch?" || { echo "Operation cancelled by user."; return 0; }
    fi

    # --- Run URL Replacements ---
    echo "1/2: Running search and replace for URLs..."
    "$WP_CLI_CMD" search-replace "//$current_domain" "//$domain" --all-tables --skip-plugins --skip-themes --report-changed-only

    echo "2/2: Running search and replace for escaped URLs..."
    "$WP_CLI_CMD" search-replace "\/\/${current_domain}" "\/\/$domain" --all-tables --skip-plugins --skip-themes --report-changed-only

    # --- Final Steps ---
    echo "Enabling search engine visibility..."
    "$WP_CLI_CMD" option update blog_public 1 --skip-plugins --skip-themes

    echo "Flushing WordPress cache..."
    "$WP_CLI_CMD" cache flush

    # Check for Kinsta environment and purge cache if present
    if [ -f "/etc/update-motd.d/00-kinsta-welcome" ] || [[ "$current_domain" == *"kinsta"* ]]; then
        echo "Kinsta environment detected. Purging Kinsta cache..."
        "$WP_CLI_CMD" kinsta cache purge --all
    fi

    echo ""
    echo "✅ Site launch complete! The new domain is '$domain'."
}

# ----------------------------------------------------
#  Migrates a site from a backup URL or local file.
#  Arguments:
#    $1 - The URL/path for the backup file.
#    $2 - A flag indicating whether to update URLs.
# ----------------------------------------------------
function migrate_site() {
    local backup_url="$1"
    local update_urls_flag="$2"

    echo "🚀 Starting Site Migration ..."

    # --- Pre-flight Checks ---
    if ! setup_wp_cli; then echo "❌ Error: WP-CLI not found." >&2; return 1; fi
    if ! command -v wget &>/dev/null; then echo "❌ Error: wget not found." >&2; return 1; fi
    if ! command -v unzip &>/dev/null; then echo "❌ Error: unzip not found." >&2; return 1; fi
    if ! command -v tar &>/dev/null; then echo "❌ Error: tar not found." >&2; return 1; fi

    local home_directory; home_directory=$(pwd)
    local wp_home; wp_home=$( "$WP_CLI_CMD" option get home --skip-themes --skip-plugins )
    if [[ "$wp_home" != "http"* ]]; then
        echo "❌ Error: WordPress not found in current directory. Migration cancelled." >&2
        return 1
    fi
    
    # --- Find Private Directory ---
    local private_dir
    if ! private_dir=$(_get_private_dir); then
        # Error message is handled by the helper function.
        echo "❌ Error: Can't locate a suitable private folder. Migration cancelled." >&2 
        return 1
    fi
    
    # --- Download and Extract Backup ---
    local timedate; timedate=$(date +'%Y-%m-%d-%H%M%S')
    local restore_dir="${private_dir}/restore_${timedate}"
    mkdir -p "$restore_dir"
    cd "$restore_dir" || return 1
    
    local local_file_name; local_file_name=$(basename "$backup_url")
    if [ -f "${home_directory}/${local_file_name}" ]; then
        mv "${home_directory}/${local_file_name}" "${private_dir}/${local_file_name}"
    fi

    #  Handle special URLs
    if [[ "$backup_url" == *"admin-ajax.php"* ]]; then
      echo "ℹ️ Backup Buddy URL found, transforming..."
      backup_url=${backup_url/wp-admin\/admin-ajax.php?action=pb_backupbuddy_backupbuddy&function=download_archive&backupbuddy_backup=/wp-content\/uploads\/backupbuddy_backups/}
    fi
    if [[ "$backup_url" == *"dropbox.com"* && "$backup_url" != *"dl=1" ]]; then
      echo "ℹ️ Dropbox URL found, adding dl=1..."
      backup_url=${backup_url/&dl=0/&dl=1}
    fi
    
    #  Download or use local file
    if [ ! -f "${private_dir}/${local_file_name}" ]; then
      echo "Downloading from $backup_url..."
      wget -q --show-progress --no-check-certificate --progress=bar:force:noscroll -O "backup_file" "$backup_url"
      if [ $? -ne 0 ]; then echo "❌ Error: Download failed."; cd "$home_directory"; return 1; fi
    else
      echo "ℹ️ Local file '${local_file_name}' found. Using it."
      mv "${private_dir}/${local_file_name}" ./backup_file
    fi

    #  Extract based on extension
    echo "Extracting backup..."
    if [[ "$backup_url" == *".zip"* || "$local_file_name" == *".zip"* ]]; then
        unzip -q -o backup_file -x "__MACOSX/*" "cgi-bin/*"
    elif [[ "$backup_url" == *".tar.gz"* || "$local_file_name" == *".tar.gz"* ]]; then
        tar xzf backup_file
    elif [[ "$backup_url" == *".tar"* || "$local_file_name" == *".tar"* ]]; then
        tar xf backup_file
    else #  Assume zip if no extension matches
        echo "ℹ️ No clear extension, assuming .zip format."
        unzip -q -o backup_file -x "__MACOSX/*" "cgi-bin/*"
    fi
    rm -f backup_file

    # --- Migrate Files ---
    local wordpresspath; wordpresspath=$( find . -type d -name 'wp-content' -print -quit )
    if [[ -z "$wordpresspath" ]]; then
      echo "❌ Error: Can't find wp-content/ in backup. Migration cancelled."; cd "$home_directory"; return 1
    fi

    echo "Migrating files..."
    # Migrate mu-plugins if found
    if [ -d "$wordpresspath/wp-content/mu-plugins" ]; then
        echo "Moving: mu-plugins"
        cd "$wordpresspath/wp-content/mu-plugins"
        for working in *; do
            echo "$working"
            if [ -f "$home_directory/wp-content/mu-plugins/$working" ]; then
                rm "$home_directory/wp-content/mu-plugins/$working"
            fi
            if [ -d "$home_directory/wp-content/mu-plugins/$working" ]; then
                rm -rf "$home_directory/wp-content/mu-plugins/$working"
            fi
                mv "$working" "$home_directory/wp-content/mu-plugins/"
        done
        cd "${private}/restore_${timedate}"
    fi

    # Migrate blogs.dir if found
    if [ -d "$wordpresspath/blogs.dir" ]; then
        echo "Moving: blogs.dir"
        rm -rf "$home_directory/wp-content/blogs.dir"
        mv "$wordpresspath/blogs.dir" "$home_directory/wp-content/"
    fi

    # Migrate gallery if found
    if [ -d "$wordpresspath/gallery" ]; then
        echo "Moving: gallery"
        rm -rf "$home_directory/wp-content/gallery"
        mv "$wordpresspath/gallery" "$home_directory/wp-content/"
    fi

    # Migrate ngg if found
    if [ -d "$wordpresspath/ngg" ]; then
        echo "Moving: ngg"
        rm -rf "$home_directory/wp-content/ngg"
        mv "$wordpresspath/ngg" "$home_directory/wp-content/"
    fi

    # Migrate uploads if found
    if [ -d "$wordpresspath/uploads" ]; then
        echo "Moving: uploads"
        rm -rf "$home_directory/wp-content/uploads"
        mv "$wordpresspath/uploads" "$home_directory/wp-content/"
    fi

    # Migrate themes if found
    for d in $wordpresspath/themes/*/; do
        echo "Moving: themes/$( basename "$d" )"
        rm -rf "$home_directory/wp-content/themes/$( basename "$d" )"
        mv "$d" "$home_directory/wp-content/themes/"
    done

    # Migrate plugins if found
    for d in $wordpresspath/plugins/*/; do
        echo "Moving: plugins/$( basename "$d" )"
        rm -rf "$home_directory/wp-content/plugins/$( basename "$d" )"
        mv "$d" "$home_directory/wp-content/plugins/"
    done
    
    #  Find and move non-default root files
    local backup_root_dir; backup_root_dir=$(dirname "$wordpresspath")
    cd "$backup_root_dir" || return 1
    local default_files=( index.php license.txt readme.html wp-activate.php wp-app.php wp-blog-header.php wp-comments-post.php wp-config-sample.php wp-cron.php wp-links-opml.php wp-load.php wp-login.php wp-mail.php wp-pass.php wp-register.php wp-settings.php wp-signup.php wp-trackback.php xmlrpc.php wp-admin wp-config.php wp-content wp-includes )
    for item in *; do
        is_default=false
        for default in "${default_files[@]}"; do
            if [[ "$item" == "$default" ]]; then is_default=true; break; fi
        done
        if ! $is_default; then
            echo "Moving root item: $item"
            mv -f "$item" "${home_directory}/"
        fi
    done
    cd "$home_directory"

    # --- Database Migration ---
    local database
    if [[ "$(uname)" == "Darwin" ]]; then
        # macOS/BSD version using stat -f
        database=$(find "$restore_dir" "$home_directory" -type f -name '*.sql' -print0 | xargs -0 stat -f '%m %N' | sort -n | tail -1 | cut -f2- -d" ")
    else
        # Linux version using find -printf
        database=$(find "$restore_dir" "$home_directory" -type f -name '*.sql' -printf '%T@ %p\n' | sort -n | tail -1 | cut -d' ' -f2-)
    fi

    if [[ -z "$database" || ! -f "$database" ]]; then
        echo "⚠️ Warning: No .sql file found in backup. Skipping database import.";
    else
        echo "Importing database from $database..."
        local search_privacy; search_privacy=$( "$WP_CLI_CMD" option get blog_public --skip-plugins --skip-themes )

        # Outputs table prefix and updates if different
        cd "${restore_dir}/${wordpresspath}/../"
        if [ -f wp-config.php ]; then
            table_prefix=$( cat wp-config.php | grep table_prefix | perl -n -e '/\047(.+)\047/&& print $1' )
        fi

        cd "$home_directory"
        current_table_prefix=$( wp config get table_prefix --skip-plugins --skip-themes )
        if [[ $table_prefix != "" && $table_prefix != "$current_table_prefix" ]]; then
            echo "Updating table prefix from $current_table_prefix to $table_prefix"
            wp config set table_prefix $table_prefix --skip-plugins --skip-themes
        fi

        # Reset the database first
        "$WP_CLI_CMD" db reset --yes --skip-plugins --skip-themes

        # Import using WP-CLI
        if ! "$WP_CLI_CMD" db import "$database"; then
            echo "  Error: Database import failed. Please check the error message above." >&2
            cd "$home_directory"
            return 1
        fi

        "$WP_CLI_CMD" cache flush --skip-plugins --skip-themes
        "$WP_CLI_CMD" option update blog_public "$search_privacy" --skip-plugins --skip-themes

        #  URL updates
        local wp_home_imported; wp_home_imported=$( "$WP_CLI_CMD" option get home --skip-plugins --skip-themes )
        if [[ "$update_urls_flag" == "true" && "$wp_home_imported" != "$wp_home" ]]; then
            echo "Updating URLs from $wp_home_imported to $wp_home..."
            "$WP_CLI_CMD" search-replace "$wp_home_imported" "$wp_home" --all-tables --report-changed-only --skip-plugins --skip-themes
        fi
    fi

    # --- Cleanup & Final Steps ---
    echo "Performing cleanup and final optimizations..."
    local plugins_to_remove=( backupbuddy wordfence w3-total-cache wp-super-cache ewww-image-optimizer )
    for plugin in "${plugins_to_remove[@]}"; do
        if "$WP_CLI_CMD" plugin is-installed "$plugin" --skip-plugins --skip-themes &>/dev/null; then
            echo "Removing plugin: $plugin"
            "$WP_CLI_CMD" plugin delete "$plugin" --skip-plugins --skip-themes
        fi
    done

    #  Convert tables to InnoDB
    local alter_queries; alter_queries=$("$WP_CLI_CMD" db query "SELECT CONCAT('ALTER TABLE ', TABLE_SCHEMA,'.', TABLE_NAME, ' ENGINE=InnoDB;') FROM information_schema.TABLES WHERE ENGINE = 'MyISAM' AND TABLE_SCHEMA=DATABASE()" --skip-column-names --skip-plugins --skip-themes)
    if [[ -n "$alter_queries" ]]; then
        echo "Converting MyISAM tables to InnoDB..."
        echo "$alter_queries" | "$WP_CLI_CMD" db query --skip-plugins --skip-themes
    fi

    "$WP_CLI_CMD" rewrite flush
    if "$WP_CLI_CMD" plugin is-active woocommerce --skip-plugins --skip-themes &>/dev/null; then
        "$WP_CLI_CMD" wc tool run regenerate_product_attributes_lookup_table --user=1 --skip-plugins --skip-themes
    fi
    
    find . -type d -exec chmod 755 {} \;
    find . -type f -exec chmod 644 {} \;
    
    #  Clean up restore directory
    rm -rf "$restore_dir"
    
    echo "✅ Site migration complete!"
}
# ----------------------------------------------------
#  Monitors server access logs in real-time.
# ----------------------------------------------------
function monitor_traffic() {
    local limit_arg="$1"
    local process_from_now="$2"

    if ! setup_gum; then
        echo "Aborting monitor: gum setup failed." >&2
        return 1
    fi

    # --- Configuration ---
    local limit=${limit_arg:-25}
    local log="$HOME/logs/access.log"
    local initial_lines_to_process=1 # How many lines to look back initially (only used with --now)
    # --- End Configuration ---

    if [ ! -f "$log" ]; then
        echo "Error: Log file not found at $log" >&2
        exit 1
    fi

    # --- Initial Setup ---
    local start_line=1 # Default: start from the beginning

    if [ "$process_from_now" = true ]; then
        echo "Processing from near the end (--now specified)." >&2
        local initial_log_count; initial_log_count=$(wc -l < "$log")
        local calculated_start=$((initial_log_count - initial_lines_to_process + 1))
        
        if [ $calculated_start -gt 1 ]; then
            start_line=$calculated_start
        else
            start_line=1
        fi
    else
        echo "Processing from the beginning of the log (line 1)." >&2
    fi

    echo "Starting analysis from line: $start_line | Top hits limit: $limit" >&2
    # --- End Initial Setup ---

    trap "echo; echo 'Monitoring stopped.'; exit 0" INT
    sleep 2 # Give user time to read initial messages

    while true; do
        local current_log_count; current_log_count=$(wc -l < "$log")
        
        if [ "$current_log_count" -lt "$start_line" ]; then
            echo "Warning: Log file appears to have shrunk or rotated. Resetting start line to 1." >&2
            start_line=1
            sleep 1
            current_log_count=$(wc -l < "$log")
            if [ "$current_log_count" -lt 1 ]; then
                echo "Log file is empty or unreadable after reset. Waiting..." >&2
                sleep 5
                continue
            fi
        fi

        local actual_lines_processed=$((current_log_count - start_line + 1))
        if [ $actual_lines_processed -lt 0 ]; then
             actual_lines_processed=0
        fi

        local overview_header="PHP Workers,Log File,Processed,From Time,To Time\n"
        local overview_data=""
        local php_workers; php_workers=$(ps -eo pid,uname,comm,%cpu,%mem,time --sort=time --no-headers | grep '[p]hp-fpm' | grep -v 'root' | wc -l)

        local first_line_time; first_line_time=$(sed -n "${start_line}p" "$log" | awk -F'[][]' '{print $2}' | head -n 1)
        [ -z "$first_line_time" ] && first_line_time="N/A"

        local last_line_time; last_line_time=$(tail -n 1 "$log" | awk -F'[][]' '{print $2}' | head -n 1)
        [ -z "$last_line_time" ] && last_line_time="N/A"

        overview_data+="$php_workers,$log,$actual_lines_processed,$first_line_time,$last_line_time\n"
        local output_header="Hits,IP Address,Status Code,Last User Agent\n"
        local output_data=""

        local top_combinations; top_combinations=$(timeout 10s sed -n "$start_line,\$p" "$log" | \
                                  awk '{print $2 " " $8}' | \
                                  sort | \
                                  uniq -c | \
                                  sort -nr | \
                                  head -n "$limit")

        if [ -z "$top_combinations" ]; then
            output_data+="0,No new data,-,\"N/A\"\n"
        else
            while IFS= read -r line; do
                line=$(echo "$line" | sed 's/^[ \t]*//;s/[ \t]*$//')
                local count ip status_code
                read -r count ip status_code <<< "$line"

                if ! [[ "$count" =~ ^[0-9]+$ ]] || [[ -z "$ip" ]] || ! [[ "$status_code" =~ ^[0-9]+$ ]]; then
                    continue
                fi

                local ip_user_agent; ip_user_agent=$(timeout 2s sed -n "$start_line,\$p" "$log" | grep " $ip " | tail -n 1 | awk -F\" '{print $6}' | cut -c 1-100)
                ip_user_agent=${ip_user_agent//,/}
                ip_user_agent=${ip_user_agent//\"/}

                [ -z "$ip_user_agent" ] && ip_user_agent="-"

                output_data+="$count,$ip,$status_code,\"$ip_user_agent\"\n"
            done < <(echo -e "$top_combinations")
        fi

        clear
        echo "--- Overview (Lines $start_line - $current_log_count | Total: $actual_lines_processed) ---"
        echo -e "$overview_header$overview_data" | "$GUM_CMD" table --print
        echo
        echo "--- Top $limit IP/Status Hits (Lines $start_line - $current_log_count) ---"
        echo -e "$output_header$output_data" | "$GUM_CMD" table --print

        sleep 2
    done
}

# ----------------------------------------------------
#  Monitors access and error logs for HTTP 500 and PHP fatal errors.
# ----------------------------------------------------
function monitor_errors() {
    if ! setup_gum; then
        echo "Aborting monitor: gum setup failed." >&2
        return 1
    fi

    # --- Find Log Files ---
    local access_log_path=""
    if [ -f "$HOME/logs/access.log" ]; then
        access_log_path="$HOME/logs/access.log"
    elif [ -f "logs/access.log" ]; then
        access_log_path="logs/access.log"
    elif [ -f "../logs/access.log" ]; then
        access_log_path="../logs/access.log"
    fi

    local error_log_path=""
    if [ -f "$HOME/logs/error.log" ]; then
        error_log_path="$HOME/logs/error.log"
    elif [ -f "logs/error.log" ]; then
        error_log_path="logs/error.log"
    elif [ -f "../logs/error.log" ]; then
        error_log_path="../logs/error.log"
    fi
    
    local files_to_monitor=()
    if [ -n "$access_log_path" ]; then
        echo "Checking for 500 errors in: $access_log_path" >&2
        files_to_monitor+=("$access_log_path")
    fi
    if [ -n "$error_log_path" ]; then
        echo "Checking for Fatal errors in: $error_log_path" >&2
        files_to_monitor+=("$error_log_path")
    fi

    if [ ${#files_to_monitor[@]} -eq 0 ]; then
        echo "No log files found in standard locations (~/logs/, logs/, ../logs/)" >&2
        return 1
    fi
    
    echo "Streaming errors from specified logs..." >&2
    echo "(Press Ctrl+C to stop)" >&2

    # --- Real-time Stream using `tail -F` ---
    tail -q -n 0 -F "${files_to_monitor[@]}" | while read -r line; do
        # Skip empty lines that might come from the pipe
        if [ -z "$line" ]; then
            continue
        fi

        # Check for the most specific term first ("Fatal") before less specific terms.
        if [[ "$line" == *"Fatal"* ]]; then
            "$GUM_CMD" log --level error "$line"
        elif [[ "$line" == *" 500 "* ]]; then
            "$GUM_CMD" log --level error "$line"
        fi
    done
}

# ----------------------------------------------------
#  Tails the access log for a clean, real-time view.
# ----------------------------------------------------
function monitor_access_log() {
    if ! setup_gum; then
        echo "Aborting monitor: gum setup failed." >&2
        return 1
    fi

    # --- Find Log File ---
    local access_log_path=""
    if [ -f "$HOME/logs/access.log" ]; then
        access_log_path="$HOME/logs/access.log"
    elif [ -f "logs/access.log" ]; then
        access_log_path="logs/access.log"
    elif [ -f "../logs/access.log" ]; then
        access_log_path="../logs/access.log"
    fi

    if [ -z "$access_log_path" ]; then
        echo "No access.log file found in standard locations (~/logs/, logs/, ../logs/)" >&2
        return 1
    fi

    echo "Streaming log: $access_log_path" >&2
    echo "(Press Ctrl+C to stop)" >&2

    # --- Real-time Stream using `tail -F` ---
    tail -n 50 -F "$access_log_path" | while read -r line; do
        # Skip empty lines
        if [ -z "$line" ]; then
            continue
        fi
        "$GUM_CMD" log --level info "$line"
    done
}

# ----------------------------------------------------
#  Tails the error log for a clean, real-time view.
# ----------------------------------------------------
function monitor_error_log() {
    if ! setup_gum; then
        echo "Aborting monitor: gum setup failed." >&2
        return 1
    fi

    # --- Find Log File ---
    local error_log_path=""
    if [ -f "$HOME/logs/error.log" ]; then
        error_log_path="$HOME/logs/error.log"
    elif [ -f "logs/error.log" ]; then
        error_log_path="logs/error.log"
    elif [ -f "../logs/error.log" ]; then
        error_log_path="../logs/error.log"
    fi

    if [ -z "$error_log_path" ]; then
        echo "No error.log file found in standard locations (~/logs/, logs/, ../logs/)" >&2
        return 1
    fi

    echo "Streaming log: $error_log_path" >&2
    echo "(Press Ctrl+C to stop)" >&2

    # --- Real-time Stream using `tail -F` ---
    tail -n 50 -F "$error_log_path" | while read -r line; do
        # Skip empty lines
        if [ -z "$line" ]; then
            continue
        fi
        "$GUM_CMD" log --level error "$line"
    done
}
# ----------------------------------------------------
#  Reset Commands
#  Handles resetting WordPress components or permissions.
# ----------------------------------------------------

# ----------------------------------------------------
#  Resets the WordPress installation to a clean, default state.
# ----------------------------------------------------
function reset_wp() {
    # This function now only accepts an optional email flag.
    # The admin user is selected interactively.
    local admin_email="$1"

    # --- Pre-flight Checks ---
    if ! setup_wp_cli; then echo "❌ Error: WP-CLI not found." >&2; return 1; fi
    if ! "$WP_CLI_CMD" core is-installed --quiet; then echo "❌ Error: This does not appear to be a WordPress installation." >&2; return 1; fi
    if ! command -v wget &>/dev/null; then echo "❌ Error: wget not found." >&2; return 1; fi
    if ! command -v unzip &>/dev/null; then echo "❌ Error: unzip not found." >&2; return 1; fi
    if ! command -v curl &>/dev/null; then echo "❌ Error: curl not found." >&2; return 1; fi
    if ! setup_gum; then echo "❌ Error: gum is required for the interactive admin picker." >&2; return 1; fi

    echo "🚀 Starting WordPress Site Reset 🚀"

    # --- Interactively Select Admin User ---
    echo "Fetching list of administrators..."
    local admin_users
    admin_users=$("$WP_CLI_CMD" user list --role=administrator --field=user_login --format=csv)
    
    if [ -z "$admin_users" ]; then
        echo "❌ Error: No administrator users found to assign to the new installation." >&2
        return 1
    fi

    local admin_user
    admin_user=$(echo "$admin_users" | "$GUM_CMD" choose --header "Select an administrator for the new installation")

    if [ -z "$admin_user" ]; then
        echo "No administrator selected. Aborting reset."
        return 0
    fi
    echo "✅ Selected administrator: $admin_user"
    # --- End Select Admin User ---

    echo "This is a destructive operation."
    # A 3-second countdown to allow the user to abort (Ctrl+C)
    for i in {3..1}; do echo -n "Continuing in $i... "; sleep 1; done; echo

    # --- Gather Info Before Reset ---
    local url; url=$( "$WP_CLI_CMD" option get home --skip-plugins --skip-themes )
    local title; title=$( "$WP_CLI_CMD" option get blogname --skip-plugins --skip-themes )

    # If admin_email flag is not supplied, get it from the selected user.
    if [ -z "$admin_email" ]; then
        admin_email=$("$WP_CLI_CMD" user get "$admin_user" --field=user_email --format=csv)
        echo "ℹ️ Admin email not provided. Using email from selected user '$admin_user': $admin_email"
    fi

    # --- Perform Reset ---
    echo "Step 1/9: Resetting the database..."
    "$WP_CLI_CMD" db reset --yes --skip-plugins --skip-themes

    echo "Step 2/9: Downloading latest WordPress core..."
    "$WP_CLI_CMD" core download --force --skip-plugins --skip-themes

    echo "Step 3/9: Installing WordPress core..."
    "$WP_CLI_CMD" core install --url="$url" --title="$title" --admin_user="$admin_user" --admin_email="$admin_email" --skip-plugins --skip-themes

    echo "Step 4/9: Deleting all other themes..."
    "$WP_CLI_CMD" theme delete --all --force --skip-plugins --skip-themes

    echo "Step 5/9: Deleting all plugins..."
    "$WP_CLI_CMD" plugin delete --all --skip-plugins --skip-themes

     echo "Step 6/9: Finding the latest default WordPress theme..."
    latest_default_theme=$("$WP_CLI_CMD" theme search twenty --field=slug --per-page=1 --quiet --skip-plugins --skip-themes)

    if [ $? -ne 0 ] || [ -z "$latest_default_theme" ]; then
      echo "❌ Error: Could not determine the latest default theme. Aborting reset."
      return 1
    fi
    echo "✅ Latest default theme is '$latest_default_theme'."
    echo "Step 7/9: Installing and activating '$latest_default_theme'..."
    "$WP_CLI_CMD" theme install "$latest_default_theme" --force --activate --skip-plugins --skip-themes

    echo "Step 8/9: Cleaning up directories (mu-plugins, uploads)..."
    rm -rf wp-content/mu-plugins/
    mkdir -p wp-content/mu-plugins/
    rm -rf wp-content/uploads/
    mkdir -p wp-content/uploads/

    echo "Step 9/9: Installing helper plugins (Kinsta MU, CaptainCore Helper)..."
    # The install_kinsta_mu function will automatically check if it's a Kinsta env.
    install_kinsta_mu
    install_helper

    echo ""
    echo "✅ WordPress reset complete!"
    echo "   URL: $url"
    echo "   Admin User: $admin_user"
}

# ----------------------------------------------------
#  Resets file and folder permissions to common defaults (755 for dirs, 644 for files).
# ----------------------------------------------------
function reset_permissions() {
    echo "Resetting file and folder permissions to defaults"
    find . -type d -exec chmod 755 {} \;
    find . -type f -exec chmod 644 {} \;
    echo "✅ Permissions have been reset."
}

# ----------------------------------------------------
#  Deactivates a suspend message by removing the mu-plugin.
# ----------------------------------------------------
function suspend_deactivate() {
    local wp_content="$1"

    #  Set default wp-content if not provided
    if [[ -z "$wp_content" ]]; then
        wp_content="wp-content"
    fi

    local suspend_file="${wp_content}/mu-plugins/do-suspend.php"

    if [ -f "$suspend_file" ]; then
        echo "Deactivating suspend message by removing ${suspend_file}..."
        rm "$suspend_file"
        echo "✅ Suspend message deactivated. Site is now live."
    else
        echo "Site appears to be already live (suspend file not found)."
    fi

    #  Clear Kinsta cache if environment is detected
    if [ -f "/etc/update-motd.d/00-kinsta-welcome" ]; then
        if setup_wp_cli && "$WP_CLI_CMD" kinsta cache purge --all --skip-themes &> /dev/null; then
            echo "Kinsta cache purged."
        else
            echo "Warning: Could not purge Kinsta cache. Is the 'wp kinsta' command available?" >&2
        fi
    fi
}

# ----------------------------------------------------
#  Activates a suspend message by adding an mu-plugin.
# ----------------------------------------------------
function suspend_activate() {
    local name="$1"
    local link="$2"
    local wp_content="$3"

    #  Set default wp-content if not provided
    if [[ -z "$wp_content" ]]; then
        wp_content="wp-content"
    fi

    #  Check for required arguments
    if [[ -z "$name" || -z "$link" ]]; then
        echo "Error: Missing required flags for 'suspend activate'." >&2
        show_command_help "suspend"
        return 1
    fi
    
    if [ ! -d "${wp_content}/mu-plugins" ]; then
        echo "Creating directory: ${wp_content}/mu-plugins"
        mkdir -p "${wp_content}/mu-plugins"
    fi

    #  Remove existing deactivation file if present
    if [ -f "${wp_content}/mu-plugins/do-suspend.php" ]; then
        echo "Removing existing suspend file..."
        rm "${wp_content}/mu-plugins/do-suspend.php"
    fi

    #  Create the deactivation mu-plugin
    local output_file="${wp_content}/mu-plugins/do-suspend.php"
    echo "Generating suspend file at ${output_file}..."
    cat <<EOF > "$output_file"
<?php
/**
 * Plugin Name: Website Suspended
 * Description: Deactivates the front-end of the website.
 */
function captaincore_template_redirect() {
    //  Return if in WP Admin or CLI
    if ( is_admin() || ( defined( 'WP_CLI' ) && WP_CLI ) ) {
        return;
    }
?>
<html>
  <head>
    <meta charset="utf-8">
    <title>Website Suspended</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
    <style>
        @import url('https://fonts.googleapis.com/css?family=Roboto');
        body {
            text-align: center;
            margin: 10% auto;
            padding: 0 15px;
            font-family: 'Roboto', sans-serif;
            overflow: hidden;
            display: block;
            max-width: 550px;
            background: #eeeeee;
        }
        p {
            margin-top: 3%;
            line-height: 1.4em;
            display: block;
        }
        img {
            margin-top: 1%;
        }
        a {
            color:#27c3f3;
        }
    </style>
  </head>
  <body>
    <div class="row">
        <div class="col s12">
            <div class="card">
                <div class="card-content">
                    <span class="card-title">Website Suspended</span>
                    <p>This website is currently unavailable.</p>
                </div>
                <div class="card-content grey lighten-4">
                    <p>Site owners may contact <a href="${link}" target="_blank" rel="noopener noreferrer">${name}</a>.</p>
                </div>
            </div>
        </div>
    </div>
  </body>
</html>
<?php
    //  Stop WordPress from loading further
    die();
}
add_action( 'template_redirect', 'captaincore_template_redirect', 1 );
EOF

    echo "✅ Generated ${output_file}"

    #  Clear Kinsta cache if environment is detected
    if [ -f "/etc/update-motd.d/00-kinsta-welcome" ]; then
        if setup_wp_cli && "$WP_CLI_CMD" kinsta cache purge --all --skip-themes &> /dev/null; then
            echo "Kinsta cache purged."
        else
            echo "Warning: Could not purge Kinsta cache. Is the 'wp kinsta' command available?" >&2
        fi
    fi
}
# ----------------------------------------------------
#  Update Commands
#  Handles WordPress core, theme, and plugin updates.
# ----------------------------------------------------

UPDATE_LOGS_DIR=""
UPDATE_LOGS_LIST_FILE=""

# ----------------------------------------------------
#  Ensures update directories and lists exist.
# ----------------------------------------------------
function _ensure_update_setup() {
    # Exit if already initialized
    if [[ -n "$UPDATE_LOGS_DIR" ]]; then return 0; fi

    local private_dir
    if ! private_dir=$(_get_private_dir); then
        return 1
    fi

    # Using the checkpoint base for consistency as updates are linked to checkpoints
    local checkpoint_base_dir="${private_dir}/checkpoints"
    UPDATE_LOGS_DIR="${checkpoint_base_dir}/updates"
    UPDATE_LOGS_LIST_FILE="$UPDATE_LOGS_DIR/list.json"

    mkdir -p "$UPDATE_LOGS_DIR"
    if [ ! -f "$UPDATE_LOGS_LIST_FILE" ]; then
        echo "[]" > "$UPDATE_LOGS_LIST_FILE"
    fi
}

# ----------------------------------------------------
#  (Helper) Lets the user select an update log from the list.
# ----------------------------------------------------
function _select_update_log() {
    _ensure_update_setup
    if ! setup_wp_cli; then return 1; fi

    if [ ! -s "$UPDATE_LOGS_LIST_FILE" ]; then
        echo "ℹ️ No update logs found. Run '_do update all' to create one." >&2
        return 1
    fi

    # Use PHP to read the detailed list and check format
    local php_script_read_list='
<?php
$list_file = "%s";
$list = json_decode(file_get_contents($list_file), true);

if (!is_array($list) || empty($list)) {
    echo "EMPTY";
    return;
}

// Check if the first item has the new detailed format.
if (!isset($list[0]["formatted_timestamp"])) {
    echo "NEEDS_GENERATE";
    return;
}

foreach($list as $item) {
    if (isset($item["formatted_timestamp"]) && isset($item["hash_before"]) && isset($item["hash_after"]) && isset($item["counts_str"]) && isset($item["diff_stats"])) {
        // Output format: formatted_timestamp|hash_before|hash_after|counts_str|diff_stats
        echo $item["formatted_timestamp"] . "|" . $item["hash_before"] . "|" . $item["hash_after"] . "|" . $item["counts_str"] . "|" . $item["diff_stats"] . "\n";
    }
}
'
    local php_script; php_script=$(printf "$php_script_read_list" "$UPDATE_LOGS_LIST_FILE")
    local update_entries; update_entries=$(echo "$php_script" | "$WP_CLI_CMD" eval-file -)

    if [[ "$update_entries" == "EMPTY" ]]; then
        echo "ℹ️ No update logs available to select." >&2; return 1;
    elif [[ "$update_entries" == "NEEDS_GENERATE" ]]; then
        echo "⚠️ The update log list needs to be generated for faster display." >&2
        echo "Please run: _do update list-generate" >&2
        return 1
    fi

    local display_items=()
    local data_items=()

    while IFS='|' read -r formatted_timestamp hash_before hash_after counts_str diff_stats; do
        hash_before=$(echo "$hash_before" | tr -d '[:space:]')
        hash_after=$(echo "$hash_after" | tr -d '[:space:]')
        if [ -z "$hash_before" ] || [ -z "$hash_after" ]; then continue; fi

        local display_string
        display_string=$(printf "%-28s | %s -> %s | %-18s | %s" \
            "$formatted_timestamp" "${hash_before:0:7}" "${hash_after:0:7}" "$counts_str" "$diff_stats")
        
        display_items+=("$display_string")
        data_items+=("$hash_before|$hash_after")
    done <<< "$update_entries"
    
    if [ ${#display_items[@]} -eq 0 ]; then
      echo "❌ No valid update entries to display." >&2
      return 1
    fi

    local prompt_text="${1:-Select an update to inspect}"
    local selected_display
    selected_display=$(printf "%s\n" "${display_items[@]}" | "$GUM_CMD" filter --height=20 --prompt="👇 $prompt_text" --indicator="→" --placeholder="")

    if [ -z "$selected_display" ]; then
        echo "" # Return empty for cancellation
        return 0
    fi

    local selected_index=-1
    for i in "${!display_items[@]}"; do
       if [[ "${display_items[$i]}" == "$selected_display" ]]; then
           selected_index=$i
           break
       fi
    done

    if [ "$selected_index" -ne -1 ]; then
        echo "${data_items[$selected_index]}"
        return 0
    else
        echo "❌ Error: Could not find selected update." >&2
        return 1
    fi
}


# ----------------------------------------------------
#  Generates a detailed list of updates for faster access.
# ----------------------------------------------------
function update_list_generate() {
    if ! setup_gum || ! setup_git; then return 1; fi
    if ! setup_wp_cli; then return 1; fi
    _ensure_checkpoint_setup # This sets up repo path as well
    _ensure_update_setup

    local php_script_read_list='
<?php
$list_file = "%s";
if (!file_exists($list_file)) { return; }
$list = json_decode(file_get_contents($list_file), true);
if (!is_array($list) || empty($list)) { return; }
foreach($list as $item) {
    // Read from both simple and potentially detailed formats
    $timestamp = $item["timestamp"] ?? "N/A";
    $hash_before = $item["before"] ?? $item["hash_before"] ?? null;
    $hash_after = $item["after"] ?? $item["hash_after"] ?? null;

    if ($timestamp && $hash_before && $hash_after) {
        echo "$timestamp|$hash_before|$hash_after\n";
    }
}
'
    local php_script; php_script=$(printf "$php_script_read_list" "$UPDATE_LOGS_LIST_FILE")
    local update_entries; update_entries=$(echo "$php_script" | "$WP_CLI_CMD" eval-file -)

    if [ -z "$update_entries" ]; then
        echo "ℹ️ No update logs found to generate a list from."
        return 0
    fi
    
    echo "🔎 Generating detailed update list... (This may take a moment)"
    local detailed_items=()

    while IFS='|' read -r timestamp hash_before hash_after; do
        hash_before=$(echo "$hash_before" | tr -d '[:space:]')
        hash_after=$(echo "$hash_after" | tr -d '[:space:]')
        if [ -z "$hash_before" ] || [ -z "$hash_after" ]; then continue; fi

        # Validate that both commits exist before proceeding
        if ! "$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" cat-file -e "${hash_before}^{commit}" &>/dev/null; then
            echo "⚠️ Warning: Could not find 'before' commit '$hash_before'. Skipping entry." >&2
            continue
        fi
        if ! "$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" cat-file -e "${hash_after}^{commit}" &>/dev/null; then
            echo "⚠️ Warning: Could not find 'after' commit '$hash_after'. Skipping entry." >&2
            continue
        fi

        local manifest_after; manifest_after=$("$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" show "$hash_after:manifest.json" 2>/dev/null)
        if [ -z "$manifest_after" ]; then
            echo "⚠️ Warning: Could not find manifest for 'after' hash '$hash_after'. Skipping entry." >&2
            continue
        fi

        local php_get_counts='
<?php
$manifest_json = <<<'EOT'
%s
EOT;
$data = json_decode($manifest_json, true);
$theme_count = isset($data["themes"]) && is_array($data["themes"]) ? count($data["themes"]) : 0;
$plugin_count = isset($data["plugins"]) && is_array($data["plugins"]) ? count($data["plugins"]) : 0;
echo "$theme_count Themes, $plugin_count Plugins";
'
        local counts_script; counts_script=$(printf "$php_get_counts" "$manifest_after")
        local counts_str; counts_str=$(echo "$counts_script" | "$WP_CLI_CMD" eval-file -)
        
        local diff_stats
        diff_stats=$("$GIT_CMD" -C "$CHECKPOINT_REPO_DIR" diff --shortstat "$hash_before" "$hash_after" -- 'plugins/' 'themes/' 'mu-plugins/' | sed 's/^[ \t]*//')
        if [ -z "$diff_stats" ]; then diff_stats="No file changes"; fi

        local formatted_timestamp
        if [[ "$(uname)" == "Darwin" ]]; then
            formatted_timestamp=$(date -j -f "%Y-%m-%dT%H:%M:%SZ" -u "$timestamp" "+%a, %b %d, %Y, %-I:%M %p")
        else
            formatted_timestamp=$(date -d "$timestamp" "+%a, %b %d, %Y, %-I:%M %p")
        fi

        local json_item
        json_item=$(printf '{"hash_before": "%s", "hash_after": "%s", "timestamp": "%s", "formatted_timestamp": "%s", "counts_str": "%s", "diff_stats": "%s"}' \
            "$hash_before" "$hash_after" "$timestamp" "$formatted_timestamp" "$counts_str" "$diff_stats")
        
        detailed_items+=("$json_item")

    done <<< "$update_entries"
    
    local full_json="["
    full_json+=$(IFS=,; echo "${detailed_items[*]}")
    full_json+="]"

    local php_write_script='
<?php
$list_file = "%s";
$json_data = <<<'EOT'
%s
EOT;
$data = json_decode($json_data, true);
file_put_contents($list_file, json_encode($data, JSON_PRETTY_PRINT));
'
    local write_script; write_script=$(printf "$php_write_script" "$UPDATE_LOGS_LIST_FILE" "$full_json")
    if echo "$write_script" | "$WP_CLI_CMD" eval-file -; then
        echo "✅ Detailed update list saved to $UPDATE_LOGS_LIST_FILE"
    else
        echo "❌ Error: Failed to write detailed update list."
    fi
}

# ----------------------------------------------------
#  Lists all past updates from the pre-generated list.
# ----------------------------------------------------
function update_list() {
    if ! setup_gum || ! setup_git; then return 1; fi
    if ! setup_wp_cli; then return 1; fi
    _ensure_checkpoint_setup # Ensures repo path is set
    
    local selected_hashes
    selected_hashes=$(_select_update_log "Select an update to inspect")

    if [ -z "$selected_hashes" ]; then
        echo "No update selected."
        return 0
    fi
    if [ $? -ne 0 ]; then
        return 1 # Error already printed by helper
    fi

    local selected_hash_before; selected_hash_before=$(echo "$selected_hashes" | cut -d'|' -f1)
    local selected_hash_after; selected_hash_after=$(echo "$selected_hashes" | cut -d'|' -f2)

    checkpoint_show "$selected_hash_after" "$selected_hash_before"
}

# ----------------------------------------------------
#  Runs the full update process.
# ----------------------------------------------------
function run_update_all() {
    if ! setup_git; then return 1; fi
    if ! command -v wp &>/dev/null; then echo "❌ Error: WP-CLI not found." >&2; return 1; fi

    _ensure_checkpoint_setup
    _ensure_update_setup

    echo "🚀 Starting full WordPress update process..."

    echo "   - Step 1/5: Creating 'before' checkpoint..."
    checkpoint_create > /dev/null
    local hash_before; hash_before=$(checkpoint_latest)
    if [ -z "$hash_before" ]; then
        echo "❌ Error: Could not create 'before' checkpoint." >&2
        return 1
    fi
    echo "     Before Hash: $hash_before"

    echo "   - Step 2/5: Running WordPress updates..."
    echo "     - Updating core..."
    "$WP_CLI_CMD" core update --skip-plugins --skip-themes
    echo "     - Updating themes..."
    "$WP_CLI_CMD" theme update --all --skip-plugins --skip-themes
    echo "     - Updating plugins..."
    "$WP_CLI_CMD" plugin update --all --skip-plugins --skip-themes

    echo "   - Step 3/5: Creating 'after' checkpoint..."
    checkpoint_create > /dev/null
    local hash_after; hash_after=$(checkpoint_latest)
    if [ -z "$hash_after" ]; then
        echo "❌ Error: Could not create 'after' checkpoint." >&2
        return 1
    fi
    echo "     After Hash: $hash_after"
    
    if [ "$hash_before" == "$hash_after" ]; then
        echo "✅ No updates were available. Site is up-to-date."
        return 0
    fi
    
    echo "   - Step 4/5: Generating update log entry..."
    local timestamp; timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

    # This creates a simple entry. `update list-generate` will enrich it later.
    local php_list_template='
<?php
$list_file = "%s";
$before = "%s";
$after = "%s";
$timestamp = "%s";
$list = file_exists($list_file) ? json_decode(file_get_contents($list_file), true) : [];
if (!is_array($list)) { $list = []; }
$new_entry = ["before" => $before, "after" => $after, "timestamp" => $timestamp];
// To keep it simple, we just read the simple format and add to it.
// The list-generate command is responsible for creating the detailed format.
$simple_list = [];
foreach($list as $item) {
    $simple_list[] = [
        "before" => $item["before"] ?? $item["hash_before"] ?? null,
        "after" => $item["after"] ?? $item["hash_after"] ?? null,
        "timestamp" => $item["timestamp"] ?? null
    ];
}
array_unshift($simple_list, $new_entry);
echo json_encode($simple_list, JSON_PRETTY_PRINT);
'
    local php_list_script; php_list_script=$(printf "$php_list_template" "$UPDATE_LOGS_LIST_FILE" "$hash_before" "$hash_after" "$timestamp")
    
    local temp_list_file; temp_list_file=$(mktemp)
    if echo "$php_list_script" | "$WP_CLI_CMD" eval-file - > "$temp_list_file"; then
        mv "$temp_list_file" "$UPDATE_LOGS_LIST_FILE"
    else
        echo "❌ Error: Failed to update master update list." >&2
        rm "$temp_list_file"
    fi

    echo "   - Step 5/5: Regenerating detailed update list..."
    update_list_generate > /dev/null

    echo "✅ Update process complete."
}

# ----------------------------------------------------
#  Upgrades the _do script to the latest version.
# ----------------------------------------------------
function run_upgrade() {
    echo "🚀 Checking for the latest version of _do..."

    # --- Pre-flight Checks ---
    if ! command -v curl &> /dev/null; then echo "❌ Error: curl is required for upgrades." >&2; return 1; fi
    if ! command -v grep &> /dev/null; then echo "❌ Error: grep is required for upgrades." >&2; return 1; fi
    if ! command -v realpath &> /dev/null; then echo "❌ Error: realpath is required for upgrades." >&2; return 1; fi
    if ! setup_gum; then return 1; fi

    # --- Download latest version to a temporary file ---
    local upgrade_url="https://github.com/CaptainCore/do/releases/latest/download/_do.sh"
    local temp_file
    temp_file=$(mktemp)
    if ! curl -sL "$upgrade_url" -o "$temp_file"; then
        echo "❌ Error: Failed to download the latest version from $upgrade_url" >&2
        rm -f "$temp_file"
        return 1
    fi

    # --- Extract version numbers ---
    local new_version
    new_version=$(grep 'CAPTAINCORE_DO_VERSION=' "$temp_file" | head -n1 | cut -d'"' -f2)

    if [ -z "$new_version" ]; then
        echo "❌ Error: Could not determine the version number from the downloaded file." >&2
        rm -f "$temp_file"
        return 1
    fi

    local current_version="$CAPTAINCORE_DO_VERSION"
    echo "   - Current version: $current_version"
    echo "   - Latest version:  $new_version"

    # --- Determine install path & type ---
    local install_path
    local current_script_path
    local is_system_install=false
    
    # Try to determine the path of the running script
    current_script_path=$(realpath "$0" 2>/dev/null)

    # Check if the script is running from a common system binary path
    if [[ -n "$current_script_path" && -f "$current_script_path" ]]; then
        if [[ "$current_script_path" == /usr/local/bin/* || "$current_script_path" == /usr/bin/* || "$current_script_path" == /bin/* ]]; then
            is_system_install=true
        fi
    fi

    # --- Handle Different Scenarios ---
    if [[ "$is_system_install" == "true" ]]; then
        # --- UPGRADE SCENARIO for an existing system install ---
        echo "   - Found existing system installation at: $current_script_path"
        install_path="$current_script_path"

        local latest_available
        latest_available=$(printf '%s\n' "$new_version" "$current_version" | sort -V | tail -n1)
        
        if [[ "$new_version" == "$current_version" ]]; then
            echo "✅ You are already using the latest version ($current_version)."
            if ! "$GUM_CMD" confirm "Do you want to reinstall it anyway?"; then
                rm -f "$temp_file"
                return 0
            fi
        elif [[ "$latest_available" == "$current_version" ]]; then
             echo "✅ You are running a newer version ($current_version) than the latest release ($new_version). No action taken."
             rm -f "$temp_file"
             return 0
        fi
        echo "   - Upgrading to version $new_version..."

    else
        # --- NEW INSTALL SCENARIO (for dev scripts or curl|bash) ---
        if [[ -n "$current_script_path" && -f "$current_script_path" ]]; then
            echo "   - Running from a local script. Treating as a new system-wide installation."
        else
             echo "   - No physical script found. Treating as a new system-wide installation."
        fi
        
        install_path="/usr/local/bin/_do"
        echo "   - Target install location: $install_path"

        # If the target already exists, check its version to avoid unnecessary work
        if [ -f "$install_path" ]; then
            local existing_install_version
            existing_install_version=$(grep 'CAPTAINCORE_DO_VERSION=' "$install_path" | head -n1 | cut -d'"' -f2)
            if [[ "$new_version" == "$existing_install_version" ]]; then
                echo "✅ The latest version ($new_version) is already installed at $install_path. No action taken."
                rm -f "$temp_file"
                return 0
            fi
        fi
    fi
    
    # --- Perform the installation/upgrade ---
    echo "   - Installing to $install_path..."

    # Make the downloaded script executable
    chmod +x "$temp_file"

    # Check for write permissions and use sudo if needed
    if [ -w "$(dirname "$install_path")" ]; then
        if ! mv "$temp_file" "$install_path"; then
            echo "❌ Error: Failed to move the new version to $install_path." >&2
            rm -f "$temp_file" # Clean up temp file on failure
            return 1
        fi
    else
        echo "   - Write permission is required for the directory $(dirname "$install_path")."
        echo "   - You may be prompted for your password to complete the installation."
        if ! sudo mv "$temp_file" "$install_path"; then
            echo "❌ Error: sudo command failed. Could not complete installation/upgrade." >&2
            rm -f "$temp_file" # Clean up temp file on failure
            return 1
        fi
    fi

    echo "✅ Success! _do version $new_version is now installed at $install_path."
}
# ----------------------------------------------------
#  Performs a full site backup to a Restic repository on B2.
#  Credentials can be injected via environment variables or piped via stdin.
# ----------------------------------------------------
function vault_create() {
    echo "🚀 Starting secure snapshot to Restic B2 repository..."

    # --- Pre-flight Checks ---
    if ! setup_restic; then return 1; fi
    if ! setup_wp_cli; then return 1; fi
    if ! "$WP_CLI_CMD" core is-installed --quiet; then
        echo "❌ Error: This does not appear to be a WordPress installation." >&2
        return 1
    fi

    # --- Setup Restic Environment ---
    if ! _setup_vault_env; then
        return 1 # Error message printed in helper
    fi

    # --- Rclone Cache Size Check ---
    if [ -n "$EMAIL_NOTIFY" ]; then
        local rclone_cache_dir="$HOME/.cache/rclone"
        if [ -d "$rclone_cache_dir" ]; then
            local cache_size_bytes
            cache_size_bytes=$(du -sb "$rclone_cache_dir" | awk '{print $1}')
            local size_limit_bytes=10737418240 # 10 GB

            if (( cache_size_bytes > size_limit_bytes )); then
                local site_url
                site_url=$("$WP_CLI_CMD" option get home)
                local cache_size_gb
                cache_size_gb=$(awk -v bytes="$cache_size_bytes" 'BEGIN { printf "%.2f", bytes / 1024 / 1024 / 1024 }')
                
                local email_subject="Rclone Cache Warning for ${site_url}"
                local email_message="Warning: The rclone cache folder at ${rclone_cache_dir} is larger than 10GB. Current size: ${cache_size_gb}GB. This might cause issues with 'vault create' operations."
                echo "   - ⚠️  Rclone cache is large (${cache_size_gb}GB). Sending email notification to $EMAIL_NOTIFY..."

                "$WP_CLI_CMD" eval "wp_mail( '$EMAIL_NOTIFY', '$email_subject', '$email_message', ['Content-Type: text/html; charset=UTF-8'] );"
            fi
        fi
    fi

    # --- Check/Initialize Restic Repository ---
    echo "   - Checking for repository at ${RESTIC_REPOSITORY}..."
    if ! "$RESTIC_CMD" stats > /dev/null 2>&1; then
        echo "   - Repository not found or is invalid. Attempting to initialize..."
        if ! "$RESTIC_CMD" init; then
            echo "❌ Error: Failed to initialize Restic repository." >&2
            return 1
        fi
        echo "   - ✅ Repository initialized successfully."
    else
        echo "   - ✅ Repository found."
    fi

    # --- Create DB Dump in Private Directory ---
    local private_dir
    if ! private_dir=$(_get_private_dir); then
        return 1
    fi
    local sql_file_path="${private_dir}/database-backup.sql"

    echo "   - Generating database dump at: ${sql_file_path}"
    if ! "$WP_CLI_CMD" db export "$sql_file_path" --add-drop-table --single-transaction --quick --max_allowed_packet=512M > /dev/null; then
        echo "❌ Error: Database export failed." >&2
        return 1
    fi

    # --- Move DB dump to root for snapshot ---
    local wp_root_dir
    wp_root_dir=$(realpath ".")
    local temporary_sql_path_in_root="${wp_root_dir}/database-backup.sql"

    echo "   - Temporarily moving database dump to web root for snapshotting."
    if ! mv "$sql_file_path" "$temporary_sql_path_in_root"; then
        echo "❌ Error: Could not move database dump to web root." >&2
        return 1
    fi

    # --- Run Restic Backup ---
    local original_dir
    original_dir=$(pwd)
    echo "   - Changing to WordPress root ($wp_root_dir) for clean snapshot paths..."
    cd "$wp_root_dir" || {
        echo "❌ Error: Could not change to WordPress root directory." >&2
        echo "   - Attempting to move database dump back to private directory..."
        mv "$temporary_sql_path_in_root" "$sql_file_path"
        return 1
    }
    
    local human_readable_size
    human_readable_size=$(du -sh . | awk '{print $1}')
    local tag_args=()
    if [[ -n "$human_readable_size" ]]; then
        tag_args+=(--tag "size:${human_readable_size}")
    fi

    echo "   - Backing up current directory (.), which now includes the SQL dump..."
    if ! "$RESTIC_CMD" backup "." \
        "${tag_args[@]}" \
        --exclude '**.DS_Store' \
        --exclude '*timthumb.txt' \
        --exclude 'debug.log' \
        --exclude 'error_log' \
        --exclude 'phperror_log' \
        --exclude 'wp-content/updraft' \
        --exclude 'wp-content/cache' \
        --exclude 'wp-content/et-cache' \
        --exclude 'wp-content/.wps-slots' \
        --exclude 'wp-content/wflogs' \
        --exclude 'wp-content/uploads/sessions' \
        --exclude 'wp-snapshots'; then
        echo "❌ Error: Restic backup command failed." >&2
        cd "$original_dir"
        echo "   - Moving database dump back to private directory..."
        mv "$temporary_sql_path_in_root" "$sql_file_path"
        return 1
    fi

    # --- Cleanup: Move DB dump back to private directory ---
    cd "$original_dir"
    echo "   - Moving database dump back to private directory..."
    mv "$temporary_sql_path_in_root" "$sql_file_path"

    # Unset variables for security
    unset B2_ACCOUNT_ID B2_ACCOUNT_KEY RESTIC_PASSWORD RESTIC_REPOSITORY

    echo "✅ Vault snapshot complete!"
}

# ----------------------------------------------------
#  (Helper) Reads credentials and sets up the restic environment.
# ----------------------------------------------------
function _setup_vault_env() {
    # --- Read Credentials ---
    local b2_bucket b2_path b2_key_id b2_app_key restic_password

    # Prioritize stdin: If data is being piped in, read from it.
    if ! [ -t 0 ]; then
        read -r stdin_b2_bucket
        read -r stdin_b2_path
        read -r stdin_b2_key_id
        read -r stdin_b2_app_key
        read -r stdin_restic_password
        
        b2_bucket=${stdin_b2_bucket}
        b2_path=${stdin_b2_path}
        b2_key_id=${stdin_b2_key_id}
        b2_app_key=${stdin_b2_app_key}
        restic_password=${stdin_restic_password}
    fi

    # If stdin empty or incomplete, then attempt to load from environment variables.
    if [ -z "$b2_bucket" ] || [ -z "$b2_path" ] || [ -z "$b2_key_id" ] || [ -z "$b2_app_key" ] || [ -z "$restic_password" ]; then
        b2_bucket="$B2_BUCKET"
        b2_path="$B2_PATH"
        b2_key_id="$B2_ACCOUNT_ID"
        b2_app_key="$B2_ACCOUNT_KEY"
        restic_password="$RESTIC_PASSWORD"
    fi

    if [ -z "$b2_bucket" ] || [ -z "$b2_path" ] || [ -z "$b2_key_id" ] || [ -z "$b2_app_key" ] || [ -z "$restic_password" ]; then
        echo "❌ Error: One or more required credentials were not provided or were empty." >&2
        return 1
    fi

    export B2_ACCOUNT_ID="$b2_key_id"
    export B2_ACCOUNT_KEY="$b2_app_key"
    export RESTIC_PASSWORD="$restic_password"
    export RESTIC_REPOSITORY="b2:${b2_bucket}:${b2_path}"

    return 0
}

# ----------------------------------------------------
#  (Helper) Caches the file list for a snapshot. 
# ----------------------------------------------------
function _cache_snapshot_files() {
    local snapshot_id="$1"
    local cache_file="$2"

    # Show a spinner while caching the entire file list. 
    if ! "$GUM_CMD" spin --spinner dot --title "Caching file list for snapshot ${snapshot_id}..." -- \
        "$RESTIC_CMD" ls --json --long --recursive "${snapshot_id}" > "$cache_file"; 
    then
        echo "❌ Error: Could not cache the file list for snapshot ${snapshot_id}." 
        >&2 
        rm -f "$cache_file" # Clean up partial cache file 
        return 1
    fi
    return 0
}

# ----------------------------------------------------
#  (Helper) Provides an interactive menu for a selected file. 
# ----------------------------------------------------
function _file_action_menu() {
    local snapshot_id="$1"
    local file_path="$2"

    local choice
    choice=$("$GUM_CMD" choose "View Content" "Download File" "Restore File" "Back")

    case "$choice" in
        "View Content")
            echo "📄 Viewing content of '$file_path'... (Press 'q' to quit)"
            local temp_file
            temp_file=$(mktemp) 
 
           
           if [ -z "$temp_file" ]; 
           then
                echo "❌ Error: Could not create a temporary file." 
                >&2 
                sleep 2
                return
            fi

            # Dump the file content to the temporary file
            if ! "$RESTIC_CMD" dump "${snapshot_id}" "${file_path}" > "$temp_file"; then 
                echo "❌ Error: Could not dump file content from repository." 
                >&2 
                rm -f "$temp_file" 
                sleep 2
                return
            fi
            
            # View the temporary file with less, ensuring it's interactive
    
             
            less -RN "$temp_file" </dev/tty
            
            # Clean up the temporary file
            rm -f "$temp_file"
            ;; 
        "Download File") 
            local filename
            filename=$(basename "$file_path") 
            echo "⬇️ Downloading '$filename' to current directory..."
            if "$GUM_CMD" confirm "Download '${filename}' to '$(pwd)'?"; 
            then
                if "$RESTIC_CMD" dump "${snapshot_id}" "${file_path}" > "$filename"; 
                then
                    local size
                    size=$(ls -lh "$filename" | awk '{print $5}') 
                    echo "✅ File downloaded: $filename ($size)"
                else
            
                     
                    echo "❌ Error: Failed to download file." 
                    rm -f "$filename" 
                fi
            else
                echo "Download cancelled." 
            fi
            "$GUM_CMD" input --placeholder="Press Enter to continue..." > /dev/null 
            ;;
        "Restore File") 
            echo "🔄 Restoring '$file_path' to current directory..."
            if "$GUM_CMD" confirm "Restore '${file_path}' to '$(pwd)'?"; 
            then
                if "$RESTIC_CMD" restore "${snapshot_id}" --include "${file_path}" --target "."; 
                then
                    echo "✅ File restored successfully." 
                else
                    echo "❌ Error: Failed to restore file." 
                fi
            else
                echo "Restore cancelled." 
            fi
            # Add a pause so the user can see the result before returning to the browser. 
            "$GUM_CMD" input --placeholder="Press Enter to continue..." > /dev/null 
            ;;
        "Back") 
            return
            ;;
        *)
    esac
}

# ----------------------------------------------------
#  (Helper) Handles the download/restore of a full folder.
# ----------------------------------------------------
function _download_folder_action() {
    local snapshot_id="$1"
    local folder_path_in_repo="$2"

    echo "📦 Preparing to download folder: '${folder_path_in_repo}'"
    echo "This action will restore the selected folder and its full directory structure from the snapshot's root into your current working directory."
    echo "For example, restoring '/wp-content/plugins/' will create the path './wp-content/plugins/' here."

    if "$GUM_CMD" confirm "Proceed with restoring '${folder_path_in_repo}' to '$(pwd)'?"; then
        echo "   - Restoring files..."
        if "$RESTIC_CMD" restore "${snapshot_id}" --include "${folder_path_in_repo}" --target "."; then
            echo "✅ Folder and its contents restored successfully."
        else
            echo "❌ Error: Failed to restore folder."
        fi
    else
        echo "Download cancelled."
    fi
    "$GUM_CMD" input --placeholder="Press Enter to continue..." > /dev/null
}

# ----------------------------------------------------
#  (Helper) Provides an interactive file browser for a snapshot.
# ----------------------------------------------------
function _browse_snapshot() {
    local snapshot_id="$1"
    local cache_file="$2"
    local current_path="/"

    while true;
    do
        clear
        echo "🗂  Browse Snapshot: ${snapshot_id} | Path: ${current_path}"

        # PHP script to parse the cached JSON and format it for the current directory
        local php_parser_code='
<?php
$cache_file = $argv[1] ?? "";
$current_path = $argv[2] ?? "/";

if (!file_exists($cache_file)) {
    fwrite(STDERR, "Cache file not found.\n");
    exit(1);
}

$file_content = file_get_contents($cache_file);
$lines = explode("\n", trim($file_content));

$items_in_current_dir = [];
$dirs_in_current_dir = [];

foreach ($lines as $line) {
    if (empty($line)) continue;
    $item = json_decode($line, true);
    if (json_last_error() !== JSON_ERROR_NONE || !isset($item["path"])) continue;

    $item_path = $item["path"];

    if (strpos($item_path, $current_path) !== 0) continue;

    $relative_path = substr($item_path, strlen($current_path));
    if (empty($relative_path)) continue;

    if (strpos($relative_path, "/") === false) {
        if ($item["type"] === "dir") {
            $dirs_in_current_dir[$relative_path] = true;
        } else {
            $items_in_current_dir[$relative_path] = $item;
        }
    } else {
        $dir_name = explode("/", $relative_path)[0];
        $dirs_in_current_dir[$dir_name] = true;
    }
}

ksort($dirs_in_current_dir);
ksort($items_in_current_dir);

if ($current_path !== "/") {
    echo "⤴️ ../ (Up one level)|up|..\n";
}

foreach (array_keys($dirs_in_current_dir) as $dir) {
    echo "📁 " . $dir . "/|dir|" . $dir . "\n";
}

foreach ($items_in_current_dir as $name => $item) {
    $size_bytes = $item["size"] ?? 0;
    $size_formatted = "0 B";
    if ($size_bytes >= 1048576) { $size_formatted = round($size_bytes / 1048576, 2) . " MB"; }
    elseif ($size_bytes >= 1024) { $size_formatted = round($size_bytes / 1024, 2) . " KB"; }
    elseif ($size_bytes > 0) { $size_formatted = $size_bytes . " B"; }
    echo "📄 " . $name . " (" . $size_formatted . ")|file|" . $name . "\n";
}

echo "\n";
echo "💾 Download this directory ({$current_path})|download_dir|.\n";
'
        # Execute PHP script to get a formatted list from the cache
        local temp_script_file;
        temp_script_file=$(mktemp)
        echo "$php_parser_code" > "$temp_script_file"
        local formatted_list;
        formatted_list=$(php -f "$temp_script_file" "$cache_file" "$current_path")
        rm "$temp_script_file"

        # --- Display and selection logic ---
        local display_items=()
        local data_items=()

        while IFS='|'
        read -r display_part type_part name_part; do
            if [ -z "$display_part" ];
            then continue; fi
            display_items+=("$display_part")
            data_items+=("${type_part}|${name_part}")
        done <<< "$formatted_list"

         local selected_display
        # Use a for loop to pipe items to gum filter, avoiding argument list limits.
        selected_display=$(
            for item in "${display_items[@]}"; do
                echo "$item"
            done | "$GUM_CMD" filter --height=20 --prompt="👇 Select a snapshot to browse" --indicator="→" --placeholder=""
        )

        if [ -z "$selected_display" ];
        then
            return # Exit the browser
        fi

        local selected_index=-1
        for i in "${!display_items[@]}";
        do
           if [[ "${display_items[$i]}" == "$selected_display" ]];
           then
               selected_index=$i
               break
           fi
        done

        if [ "$selected_index" -eq -1 ];
        then continue; fi

        local selected_data="${data_items[selected_index]}"
        local item_type;
        item_type=$(echo "$selected_data" | cut -d'|' -f1)
        local item_name;
        item_name=$(echo "$selected_data" | cut -d'|' -f2)

        case "$item_type" in
            "dir")
                current_path="${current_path}${item_name}/"
                ;;
            "file")
                _file_action_menu "${snapshot_id}" "${current_path}${item_name}"
                ;;
            "up")
                if [[ "$current_path" != "/" ]]; then
                    # Get parent directory
                    parent_path=$(dirname "${current_path%/}")
                    # If the parent is the root, the new path is simply "/".
                    # Otherwise, it's the parent path with a trailing slash.
                    if [[ "$parent_path" == "/" ]]; then
                        current_path="/"
                    else
                        current_path="${parent_path}/"
                    fi
                fi
                ;;
            "download_dir")
                _download_folder_action "${snapshot_id}" "${current_path}"
                ;;
        esac
    done
}

# ----------------------------------------------------
#  Lists all snapshots in the Restic repository.
# ----------------------------------------------------
function vault_snapshots() {
    local output_mode="$1"

    if ! setup_restic; then return 1; fi
    if ! setup_gum; then return 1; fi
    if ! command -v php &>/dev/null; then echo "❌ Error: The 'php' command is required for this operation." >&2; return 1; fi
    if ! command -v mktemp &>/dev/null; then echo "❌ Error: The 'mktemp' command is required for this operation." >&2; return 1; fi
    if ! command -v wc &>/dev/null; then echo "❌ Error: The 'wc' command is required for this operation." >&2; return 1; fi

    if ! _setup_vault_env; then
        return 1 # Error message printed in helper
    fi

    local snapshots_json
    snapshots_json=$("$GUM_CMD" spin --spinner dot --title "Fetching snapshots from repository..." -- \
    "$RESTIC_CMD" snapshots --json
)
    if [[ ! "$snapshots_json" =~ ^\[ ]]; then
        echo "Error: Failed to fetch snapshots. Restic output:" >&2
        echo "$snapshots_json" >&2
        exit 1
    fi

    local total_count
    read -r -d '' php_script << 'EOF'
    $json_string = file_get_contents("php://stdin");
    $snapshots = json_decode($json_string, true);
    if (json_last_error() === JSON_ERROR_NONE) {
        echo count($snapshots);
    } else {
        echo 0;
    }
EOF
    total_count=$("$GUM_CMD" spin --spinner dot --title "Counting total snapshots..." -- \
        bash -c 'php -r "$1"' _ "$php_script" <<< "$snapshots_json"
    )

    echo "🔎 Fetching ${total_count} snapshots..."

    if [[ "$snapshots_json" == "[]" ]]; then
        echo "ℹ️ No snapshots found in the repository."
        return 0
    fi

    local php_parser_code='
<?php
if (defined("STDIN")) {
    $json_data = file_get_contents("php://stdin");
    $snapshots = json_decode($json_data, true);
    if (json_last_error() !== JSON_ERROR_NONE) {
        fwrite(STDERR, "PHP Error: Failed to decode JSON - " . json_last_error_msg() . "\n");
        exit(1);
    }
    if (empty($snapshots) || !is_array($snapshots)) {
        exit(0);
    }
    usort($snapshots, function($a, $b) { return strtotime($b["time"]) - strtotime($a["time"]); });

    foreach ($snapshots as $snap) {
        $size_formatted = "N/A";
        if (isset($snap["summary"]["total_bytes_processed"])) {
            $size_bytes = (float)$snap["summary"]["total_bytes_processed"];
            if ($size_bytes >= 1073741824) {
                $size_formatted = round($size_bytes / 1073741824, 2) . " GB";
            } elseif ($size_bytes >= 1048576) {
                $size_formatted = round($size_bytes / 1048576, 2) . " MB";
            } elseif ($size_bytes >= 1024) {
                $size_formatted = round($size_bytes / 1024, 2) . " KB";
            } elseif ($size_bytes > 0) {
                $size_formatted = $size_bytes . " B";
            }
        }

        echo $snap["short_id"] . "|" .
             (new DateTime($snap["time"]))->format("Y-m-d H:i:s") . "|" .
             $size_formatted . "\n";
    }
}
'
    local php_script_file
    php_script_file=$(mktemp)
    if [ -z "$php_script_file" ]; then
        echo "❌ Error: Could not create a temporary file for the PHP script." >&2
        return 1
    fi

    echo "$php_parser_code" > "$php_script_file"
    local snapshot_list
    snapshot_list=$(printf "%s" "$snapshots_json" | php -f "$php_script_file" 2>/dev/null)
    rm -f "$php_script_file"

    if [ -z "$snapshot_list" ]; then
        echo "❌ Error parsing snapshot list." >&2
        return 1
    fi

    local display_items=()
    local data_items=()

    while IFS='|' read -r id time size; do
        if [ -z "$id" ]; then
            continue
        fi
        display_items+=("$(printf "%-9s | %-20s | %-10s" "$id" "$time" "$size")")
        data_items+=("$id")
    done <<< "$snapshot_list"

    if [[ "$output_mode" == "true" ]]; then
        printf "%s\n" "${display_items[@]}"
        return 0
    fi

    local selected_display
    selected_display=$(printf "%s\n" "${display_items[@]}" | "$GUM_CMD" filter --height=20 --prompt="👇 Select a snapshot to browse" --indicator="→" --placeholder="")

    if [ -z "$selected_display" ]; then echo "No snapshot selected."; return 0; fi

    local selected_id
    selected_id=$(echo "$selected_display" | awk '{print $1}')

    local cache_file;
    cache_file=$(mktemp)
    if ! _cache_snapshot_files "$selected_id" "$cache_file"; then
        [ -f "$cache_file" ] && rm -f "$cache_file"
        return 1
    fi

    _browse_snapshot "$selected_id" "$cache_file"
    rm -f "$cache_file"
}

# ----------------------------------------------------
#  Mounts the Restic repository to a local directory. 
# ----------------------------------------------------
function vault_mount() {
    echo "🚀 Preparing to mount Restic repository..."
    if ! setup_restic; 
    then return 1; fi
    if ! _setup_vault_env; then return 1; 
    fi

    local mount_point="/tmp/restic_mount_$(date +%s)"
    mkdir -p "$mount_point"

    echo "   - Mount point created at: $mount_point"
    echo "   - To unmount, run: umount \"$mount_point\""
    echo "   - Press Ctrl+C to stop the foreground mount process."
    "$RESTIC_CMD" mount "$mount_point" 
}

# ----------------------------------------------------
#  Displays statistics about the Restic repository.
# ----------------------------------------------------
function vault_info() {
    echo "🔎 Gathering repository information..."

    # --- Pre-flight Checks ---
    if ! setup_restic; then return 1; fi
    if ! setup_gum; then return 1; fi
    if ! setup_rclone; then return 1; fi
    if ! command -v php &>/dev/null; then echo "❌ Error: The 'php' command is required for this operation." >&2; return 1; fi

    if ! _setup_vault_env; then
        return 1 # Error message printed in helper
    fi

    # --- Get repo size and file count using rclone ---
    local temp_repo_string="${RESTIC_REPOSITORY#b2:}"
    local b2_bucket="${temp_repo_string%%:*}"
    local b2_path="${temp_repo_string#*:}"
    local rclone_remote_string=":b2,account='${B2_ACCOUNT_ID}',key='${B2_ACCOUNT_KEY}':${b2_bucket}/${b2_path}"
    
    local size_json
    size_json=$("$GUM_CMD" spin --spinner dot --title "Calculating repository size with rclone..." -- \
        "$RCLONE_CMD" size --json "$rclone_remote_string"
    )

    local size_data=""
    if [[ "$size_json" == *"bytes"* ]]; then
        local size_parser_code='
$json_str = file_get_contents("php://stdin");
$data = json_decode($json_str, true);
if (json_last_error() === JSON_ERROR_NONE) {
    $bytes = $data["bytes"] ?? 0;
    $count = $data["count"] ?? 0;
    $size_formatted = "0 B";
    if ($bytes >= 1073741824) { $size_formatted = round($bytes / 1073741824, 2) . " GiB"; }
    elseif ($bytes >= 1048576) { $size_formatted = round($bytes / 1048576, 2) . " MiB"; }
    elseif ($bytes >= 1024) { $size_formatted = round($bytes / 1024, 2) . " KiB"; }
    elseif ($bytes > 0) { $size_formatted = $bytes . " B"; }
    echo "Total Size," . $size_formatted . "\n";
    echo "Total Files," . $count . "\n";
}
'
        size_data=$(echo "$size_json" | php -r "$size_parser_code")
    fi

    # --- Get Snapshot Info from Restic ---
    local snapshots_json
    snapshots_json=$("$GUM_CMD" spin --spinner dot --title "Fetching snapshot list..." -- \
        "$RESTIC_CMD" snapshots --json)
    
    if [ $? -ne 0 ]; then
        echo "❌ Error fetching snapshots from restic." >&2
        echo "Restic output: $snapshots_json" >&2
        return 1
    fi

    # Verify JSON and default to empty array if invalid
    if ! printf "%s" "$snapshots_json" | "$GUM_CMD" format >/dev/null 2>&1; then
        snapshots_json="[]"
    fi
    
    # --- MODIFIED: Pipe Restic JSON directly to PHP parser ---
    local php_parser_code_info='
$json_data = file_get_contents("php://stdin");
$snapshots = json_decode($json_data, true);

// Exit if JSON is invalid or empty after decoding
if (json_last_error() !== JSON_ERROR_NONE || !is_array($snapshots)) { exit(0); }

$snapshot_count = count($snapshots); 
$oldest_date = "N/A"; 
$newest_date = "N/A"; 

if ($snapshot_count > 0) {
    $timestamps = array_map(function($s) {
        return isset($s["time"]) ? strtotime($s["time"]) : 0;
    }, $snapshots);
    $timestamps = array_filter($timestamps); 
    if(count($timestamps) > 0) {
        $oldest_ts = min($timestamps);
        $newest_ts = max($timestamps); 
        $oldest_date = date("Y-m-d H:i:s T", $oldest_ts);
        $newest_date = date("Y-m-d H:i:s T", $newest_ts);
    }
}
echo "Snapshot Count," . $snapshot_count . "\n"; 
echo "Oldest Snapshot," . $oldest_date . "\n"; 
echo "Newest Snapshot," . $newest_date . "\n";
'
    local info_data
    info_data=$(printf "%s" "$snapshots_json" | php -r "$php_parser_code_info")
    
    echo "--- Repository Information ---"
    (
      echo "Statistic,Value"
      echo "B2 Bucket,${b2_bucket}"
      echo "B2 Path,${b2_path}"
      if [ -n "$size_data" ]; then echo "$size_data"; fi
      if [ -n "$info_data" ]; then echo "$info_data"; fi
    ) | "$GUM_CMD" table --print --separator "," --widths=20,40
}

# ----------------------------------------------------
#  Prunes the Restic repository to remove unneeded data.
# ----------------------------------------------------
function vault_prune() {
    echo "🚀 Preparing to prune the Restic repository..."
    echo "This command removes old data that is no longer needed."
    echo "It can be a long-running process and will lock the repository."

    # --- Pre-flight Checks ---
    if ! setup_restic; then return 1; fi
    if ! setup_gum; then return 1; fi

    # --- Setup Restic Environment ---
    if ! _setup_vault_env; then
        return 1 # Error message printed in helper
    fi

    # --- User Confirmation ---
    echo "Repository: ${RESTIC_REPOSITORY}"
    if ! "$GUM_CMD" confirm "Are you sure you want to prune this repository?"; then
        echo "Prune operation cancelled."
        unset B2_ACCOUNT_ID B2_ACCOUNT_KEY RESTIC_PASSWORD RESTIC_REPOSITORY
        return 0
    fi

    # --- Run Restic Prune with lock detection ---
    echo "   - Starting prune operation. This may take a while..."
    local prune_output
    # Capture all output (stdout and stderr) to check for the lock message
    prune_output=$("$RESTIC_CMD" prune 2>&1)
    local prune_exit_code=$?

    # Check if the prune command failed
    if [ $prune_exit_code -ne 0 ]; then
        # If it failed, check if it was due to a lock
        if echo "$prune_output" | grep -q "unable to create lock"; then
            echo "⚠️ The repository is locked. A previous operation may have failed or is still running."
            echo "$prune_output" # Show the user the detailed lock info from restic
            
            if "$GUM_CMD" confirm "Do you want to attempt to remove the stale lock and retry?"; then
                echo "   - Attempting to unlock repository..."
                if ! "$RESTIC_CMD" unlock; then
                    echo "❌ Error: Failed to unlock the repository. Please check it manually." >&2
                    unset B2_ACCOUNT_ID B2_ACCOUNT_KEY RESTIC_PASSWORD RESTIC_REPOSITORY
                    return 1
                fi
                
                echo "   - Unlock successful. Retrying prune operation..."
                if ! "$RESTIC_CMD" prune; then
                     echo "❌ Error: Restic prune command failed even after unlocking." >&2
                     unset B2_ACCOUNT_ID B2_ACCOUNT_KEY RESTIC_PASSWORD RESTIC_REPOSITORY
                     return 1
                fi
            else
                echo "Prune operation cancelled due to locked repository."
                unset B2_ACCOUNT_ID B2_ACCOUNT_KEY RESTIC_PASSWORD RESTIC_REPOSITORY
                return 0
            fi
        else
            # The failure was for a reason other than a lock
            echo "❌ Error: Restic prune command failed." >&2
            echo "$prune_output" >&2
            unset B2_ACCOUNT_ID B2_ACCOUNT_KEY RESTIC_PASSWORD RESTIC_REPOSITORY
            return 1
        fi
    fi

    # --- Cleanup ---
    unset B2_ACCOUNT_ID B2_ACCOUNT_KEY RESTIC_PASSWORD RESTIC_REPOSITORY

    echo "✅ Vault prune complete!"
}

# ----------------------------------------------------
#  Deletes a specific snapshot from the Restic repository.
# ----------------------------------------------------
function vault_delete() {
    local snapshot_id="$1"

    if [ -z "$snapshot_id" ]; then
        echo "❌ Error: You must provide a snapshot ID to delete." >&2
        show_command_help "vault" >&2
        return 1
    fi

    # --- Pre-flight Checks ---
    if ! setup_restic; then return 1; fi
    if ! setup_gum; then return 1; fi

    # --- Setup Restic Environment ---
    if ! _setup_vault_env; then
        return 1 # Error message printed in helper
    fi

    echo "You are about to permanently delete snapshot: ${snapshot_id}"
    echo "This action cannot be undone."
    if ! "$GUM_CMD" confirm "Are you sure you want to delete this snapshot?"; then
        echo "Delete operation cancelled."
        unset B2_ACCOUNT_ID B2_ACCOUNT_KEY RESTIC_PASSWORD RESTIC_REPOSITORY
        return 0
    fi

    echo "   - Deleting snapshot ${snapshot_id}..."
    local forget_output
    # Capture stdout and stderr to check for errors
    forget_output=$("$RESTIC_CMD" forget "$snapshot_id" 2>&1)
    local forget_exit_code=$?

    # Check if the command failed
    if [ $forget_exit_code -ne 0 ]; then
        # If it failed, check if it was due to a lock
        if echo "$forget_output" | grep -q "unable to create lock"; then
            echo "⚠️ The repository is locked. A previous operation may have failed or is still running."
            echo "$forget_output"
            
            if "$GUM_CMD" confirm "Do you want to attempt to remove the stale lock and retry?"; then
                echo "   - Attempting to unlock repository..."
                if ! "$RESTIC_CMD" unlock; then
                    echo "❌ Error: Failed to unlock the repository. Please check it manually." >&2
                    unset B2_ACCOUNT_ID B2_ACCOUNT_KEY RESTIC_PASSWORD RESTIC_REPOSITORY
                    return 1
                fi
                
                echo "   - Unlock successful. Retrying delete operation..."
                if ! "$RESTIC_CMD" forget "$snapshot_id"; then
                     echo "❌ Error: Restic forget command failed even after unlocking." >&2
                     unset B2_ACCOUNT_ID B2_ACCOUNT_KEY RESTIC_PASSWORD RESTIC_REPOSITORY
                     return 1
                fi
            else
                echo "Delete operation cancelled due to locked repository."
                unset B2_ACCOUNT_ID B2_ACCOUNT_KEY RESTIC_PASSWORD RESTIC_REPOSITORY
                return 0
            fi
        else
            # The failure was for a reason other than a lock
            echo "❌ Error: Failed to delete snapshot ${snapshot_id}." >&2
            echo "$forget_output" >&2
            unset B2_ACCOUNT_ID B2_ACCOUNT_KEY RESTIC_PASSWORD RESTIC_REPOSITORY
            return 1
        fi
    else
        # Print the success output from the first attempt
        echo "$forget_output"
    fi

    # --- Cleanup ---
    unset B2_ACCOUNT_ID B2_ACCOUNT_KEY RESTIC_PASSWORD RESTIC_REPOSITORY

    echo "✅ Snapshot ${snapshot_id} has been forgotten."
    echo "💡 Note: This only removes the snapshot reference. To free up storage space by removing the underlying data, run '_do vault prune'."
}

function vault_snapshot_info() {
    local snapshot_id="$1"

    if [ -z "$snapshot_id" ];
    then
        echo "❌ Error: You must provide a snapshot ID."
        show_command_help "vault" >&2
        return 1
    fi

    # --- Pre-flight Checks ---
    if ! setup_restic; then return 1; fi
    if ! setup_gum; then return 1; fi
    if ! command -v php &>/dev/null; then
        echo "❌ Error: The 'php' command is required for this operation."
        >&2
        return 1
    fi

    # --- Setup Restic Environment ---
    if ! _setup_vault_env; then
        return 1
    fi

    # --- Fetch Snapshot Data ---
    echo "🔎 Fetching information for snapshot ${snapshot_id}..."
    local snapshots_json
    snapshots_json=$("$GUM_CMD" spin --spinner dot --title "Fetching repository data..." -- \
        "$RESTIC_CMD" snapshots --json)

    if [ $? -ne 0 ]; then
        echo "❌ Error: Failed to fetch snapshot list from the repository."
        >&2
        unset B2_ACCOUNT_ID B2_ACCOUNT_KEY RESTIC_PASSWORD RESTIC_REPOSITORY
        return 1
    fi

    # --- PHP Parser ---
    # This script searches the JSON list for the specific snapshot ID and falls back to 'restic stats' if needed.
    local php_parser_code='
$target_id = $argv[1] ?? "";
$restic_cmd = $argv[2] ?? "restic";

if (empty($target_id)) { exit(1);
}

$json_data = file_get_contents("php://stdin");
$snapshots = json_decode($json_data, true);
if (json_last_error() !== JSON_ERROR_NONE || !is_array($snapshots)) {
    exit(1);
}

$found_snap = null;
foreach ($snapshots as $snap) {
    if ((isset($snap["id"]) && strpos($snap["id"], $target_id) === 0) || (isset($snap["short_id"]) && $snap["short_id"] === $target_id)) {
        $found_snap = $snap;
        break;
    }
}

if ($found_snap === null) {
    fwrite(STDERR, "Snapshot with ID starting with \"$target_id\" not found.\n");
    exit(1);
}

$snap = $found_snap;

function format_bytes($bytes) {
    $bytes = (float)$bytes;
    if ($bytes >= 1073741824) { return round($bytes / 1073741824, 2) . " GB"; }
    elseif ($bytes >= 1048576) { return round($bytes / 1048576, 2) . " MB"; }
    elseif ($bytes >= 1024) { return round($bytes / 1024, 2) . " KB"; }
    elseif ($bytes > 0) { return $bytes . " B"; }
    else { return "0 B"; }
}

$output = [];
$output["ID"] = $snap["short_id"] ?? "N/A";
$output["Time"] = isset($snap["time"]) ? (new DateTime($snap["time"]))->format("Y-m-d H:i:s T") : "N/A";
$output["Parent"] = $snap["parent"] ?? "None";
$output["Paths"] = isset($snap["paths"]) && is_array($snap["paths"]) ? implode("\n", $snap["paths"]) : "N/A";

$size_formatted = "N/A";
$data_added_formatted = "N/A";

if (isset($snap["summary"]["total_bytes_processed"])) {
    $size_formatted = format_bytes($snap["summary"]["total_bytes_processed"]);
    if (isset($snap["summary"]["data_added"])) {
        $data_added_formatted = format_bytes($snap["summary"]["data_added"]);
    }
} else {
    fwrite(STDERR, "Snapshot summary not found. Calculating size with '\''restic stats'\''.\n");
    $full_snapshot_id = $snap["id"];
    $stats_json = shell_exec(escapeshellarg($restic_cmd) . " stats --json " . escapeshellarg($full_snapshot_id));
    if ($stats_json) {
        $stats_data = json_decode($stats_json, true);
        if (json_last_error() === JSON_ERROR_NONE && isset($stats_data["total_size"])) {
            $size_formatted = format_bytes($stats_data["total_size"]);
        }
    }
}

$output["Size (Full)"] = $size_formatted;
$output["Data Added (Unique)"] = $data_added_formatted;

foreach($output as $key => $value) {
    // Using addslashes and quoting to handle multi-line paths and other special characters
    echo $key . "," . "\"" . addslashes($value) . "\"\n";
}
'
    # --- Process and Display ---
    local info_data
    info_data=$(echo "$snapshots_json" | php -r "$php_parser_code" "$snapshot_id" "$RESTIC_CMD")

    # If the PHP script returns no data, the snapshot was not found in the JSON.
    if [ -z "$info_data" ]; then
        echo "❌ Error: Could not find data for snapshot '${snapshot_id}' in the repository list." >&2
        unset B2_ACCOUNT_ID B2_ACCOUNT_KEY RESTIC_PASSWORD RESTIC_REPOSITORY
        return 1
    fi

    # Unset variables for security
    unset B2_ACCOUNT_ID B2_ACCOUNT_KEY RESTIC_PASSWORD RESTIC_REPOSITORY

    # Display the final table
    echo "--- Snapshot Information ---"
    (
      echo "Property,Value"
      # The PHP script now correctly escapes output for the table
      echo "$info_data"
    ) |
    "$GUM_CMD" table --print --separator "," --widths=25,0

}
# ----------------------------------------------------
#  Displays the version of the _do script.
# ----------------------------------------------------
function show_version() {
    echo "_do version $CAPTAINCORE_DO_VERSION"
}
# ----------------------------------------------------
#  Checks for and identifies sources of WP-CLI warnings.
# ----------------------------------------------------
function wpcli_check() {
    if ! setup_wp_cli; then echo "❌ Error: WP-CLI not found." >&2; return 1; fi
    if ! "$WP_CLI_CMD" core is-installed --quiet; then echo "❌ Error: This does not appear to be a WordPress installation." >&2; return 1; fi

    echo "🚀 Checking for WP-CLI warnings..."

    # 1. Run with everything skipped to check for core issues.
    local base_warnings
    base_warnings=$("$WP_CLI_CMD" plugin list --skip-themes --skip-plugins 2>&1 >/dev/null)

    if [[ -n "$base_warnings" ]]; then
        echo "⚠️ Found warnings even with all plugins and themes skipped. This might be a WP-CLI core or WordPress core issue."
        echo "--- Warnings ---"
        echo "$base_warnings"
        echo "----------------"
        return 1
    fi

    # 2. Run with everything active to get a baseline.
    local initial_warnings
    initial_warnings=$("$WP_CLI_CMD" plugin list 2>&1 >/dev/null)

    if [[ -z "$initial_warnings" ]]; then
        echo "✅ WP-CLI is running smoothly. No warnings detected."
        return 0
    fi

    echo "⚠️ WP-CLI produced warnings. Investigating the source..."
    echo
    echo "--- Initial Warnings Found ---"
    echo "$initial_warnings"
    echo "----------------------------"
    echo

    local culprit_found=false

    # 3. Check theme impact
    echo "Testing for theme conflicts..."
    local warnings_without_theme
    warnings_without_theme=$("$WP_CLI_CMD" plugin list --skip-themes 2>&1 >/dev/null)
    if [[ -z "$warnings_without_theme" ]]; then
        local active_theme
        active_theme=$("$WP_CLI_CMD" theme list --status=active --field=name)
        echo "✅ Problem resolved by skipping themes. The active theme '$active_theme' is the likely source of the warnings."
        culprit_found=true
    else
        echo "No warnings seem to originate from the theme."
    fi

    # 4. Check plugin impact
    echo "Testing for plugin conflicts..."
    local active_plugins=()
    while IFS= read -r line; do
        active_plugins+=("$line")
    done < <("$WP_CLI_CMD" plugin list --field=name --status=active)

    if [[ ${#active_plugins[@]} -eq 0 ]]; then
        echo "ℹ️ No active plugins found to test."
    else
        echo "Comparing output when skipping each of the ${#active_plugins[@]} active plugins..."
        for plugin in "${active_plugins[@]}"; do
            printf "  - Testing by skipping '%s'... " "$plugin"
            local warnings_without_plugin
            warnings_without_plugin=$("$WP_CLI_CMD" plugin list --skip-plugins="$plugin" 2>&1 >/dev/null)

            if [[ -z "$warnings_without_plugin" ]]; then
                printf "FOUND CULPRIT\n"
                echo "  ✅ Warnings disappeared when skipping '$plugin'. This plugin is a likely source of the warnings."
                culprit_found=true
            else
                 printf "no change\n"
            fi
        done
    fi
    echo
    if ! $culprit_found; then
        echo "ℹ️ Could not isolate a single plugin or theme as the source. The issue might be from a combination of plugins or WordPress core itself."
    fi
    echo "✅ Check complete."
}

# ----------------------------------------------------
#  Creates a zip archive of a specified folder.
# ----------------------------------------------------
function run_zip() {
    local target_folder="$1"

    # --- 1. Validate Input ---
    if [ -z "$target_folder" ]; then
        echo "Error: No folder specified." >&2
        echo "Usage: _do zip \"<folder>\"" >&2
        return 1
    fi

    if [ ! -d "$target_folder" ]; then
        echo "Error: Folder '$target_folder' not found." >&2
        return 1
    fi

    if ! command -v realpath &> /dev/null; then
        echo "Error: 'realpath' command is required but not found." >&2
        return 1
    fi

    # --- 2. Determine Paths and Names ---
    local full_target_path
    full_target_path=$(realpath "$target_folder")
    local parent_dir
    parent_dir=$(dirname "$full_target_path")
    local dir_to_zip
    dir_to_zip=$(basename "$full_target_path")
    local output_zip_file="${dir_to_zip}.zip"
    local output_zip_path="${parent_dir}/${output_zip_file}"

    # Prevent zipping to the same name if it already exists
    if [ -f "$output_zip_path" ]; then
        echo "Error: A file named '${output_zip_file}' already exists in the target directory." >&2
        return 1
    fi

    echo "🚀 Creating zip archive for '${dir_to_zip}'..."

    # --- 3. Create Zip Archive ---
    # Change to the parent directory to ensure clean paths inside the zip
    local original_dir
    original_dir=$(pwd)
    cd "$parent_dir" || { echo "Error: Could not change to directory '$parent_dir'." >&2; return 1; }

    # Create the zip file, excluding common unnecessary files
    if ! zip -r "$output_zip_file" "$dir_to_zip" -x "*.git*" "*.DS_Store*" "*node_modules*" > /dev/null; then
        echo "Error: Failed to create zip archive." >&2
        cd "$original_dir"
        return 1
    fi

    # Return to the original directory
    cd "$original_dir"

    # --- 4. Final Report ---
    local file_size
    file_size=$(du -h "$output_zip_path" | cut -f1 | xargs)
    local final_output_path="$output_zip_path"

    # --- WordPress URL Logic ---
    local zip_url=""
    # Silently check if WP-CLI is available and we're in a WordPress installation.
    # This check works by traversing up from the current directory.
    if setup_wp_cli &>/dev/null && "$WP_CLI_CMD" core is-installed --quiet 2>/dev/null; then
        local wp_home
        wp_home=$("$WP_CLI_CMD" option get home --skip-plugins --skip-themes 2>/dev/null)
        
        if [ -n "$wp_home" ]; then
            local wp_root_path
            # Use `wp config path` to reliably find the WP root.
            wp_root_path=$("$WP_CLI_CMD" config path --quiet 2>/dev/null)
            
            if [ -n "$wp_root_path" ] && [ -f "$wp_root_path" ]; then
                wp_root_path=$(dirname "$wp_root_path")
                
                # The zip file is created in `parent_dir`. We need its path relative to the WP root.
                local relative_zip_dir_path
                relative_zip_dir_path=${parent_dir#"$wp_root_path"}
                
                # Construct the final URL
                zip_url="${wp_home%/}${relative_zip_dir_path}/${output_zip_file}"
            fi
        fi
    fi
    # --- End WordPress URL Logic ---

    echo "✅ Zip archive created successfully."
    if [ -n "$zip_url" ]; then
        echo "   Link: $zip_url ($file_size)"
    else
        echo "   File: $final_output_path ($file_size)"
    fi
}

#  Pass all script arguments to the main function.
main "$@"
