#!/bin/bash
# PHP Configuration Manager
# Handles backup, restore, and modification of PHP configurations
# Part of Server Toolkit - Configuration Management

# Source required dependencies
_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$_LIB_DIR/php-detector.sh" 2>/dev/null || { echo "ERROR: php-detector.sh not found"; return 1; }

# Backup directory
BACKUP_DIR="/root/server-toolkit/backups/php"
BACKUP_TIMESTAMP=$(date +%Y%m%d_%H%M%S)

# ============================================================================
# BACKUP FUNCTIONS
# ============================================================================

# Create backup directory structure
initialize_backup_system() {
    mkdir -p "$BACKUP_DIR"

    if [ ! -d "$BACKUP_DIR" ]; then
        echo "ERROR: Failed to create backup directory: $BACKUP_DIR"
        return 1
    fi

    return 0
}

# Backup a single PHP configuration file
# Usage: backup_php_config <config_file> [backup_name]
backup_php_config() {
    local config_file="$1"
    local backup_name="${2:-$BACKUP_TIMESTAMP}"

    if [ ! -f "$config_file" ]; then
        echo "ERROR: Config file not found: $config_file"
        return 1
    fi

    # Create backup subdirectory
    local backup_subdir="$BACKUP_DIR/$backup_name"
    mkdir -p "$backup_subdir"

    # Preserve directory structure
    local relative_path="${config_file#/}"
    local backup_path="$backup_subdir/$relative_path"
    local backup_dir_path=$(dirname "$backup_path")

    mkdir -p "$backup_dir_path"

    # Copy with metadata preservation
    cp -p "$config_file" "$backup_path"

    if [ $? -eq 0 ]; then
        echo "$backup_path"
        return 0
    else
        echo "ERROR: Failed to backup $config_file"
        return 1
    fi
}

# Backup PHP-FPM pool configuration
# Usage: backup_fpm_pool <username> [backup_name]
backup_fpm_pool() {
    local username="$1"
    local backup_name="${2:-$BACKUP_TIMESTAMP}"

    # Source php-detector to find pool config
    local pool_config
    pool_config=$(find_fpm_pool_config "$username")

    if [ -z "$pool_config" ] || [ ! -f "$pool_config" ]; then
        echo "ERROR: FPM pool config not found for $username"
        return 1
    fi

    backup_php_config "$pool_config" "$backup_name"
}

# Backup all PHP configs for a user
# Usage: backup_user_php_configs <username> <domain> [backup_name]
backup_user_php_configs() {
    local username="$1"
    local domain="$2"
    local backup_name="${3:-$BACKUP_TIMESTAMP}"

    initialize_backup_system || return 1

    local backup_subdir="$BACKUP_DIR/$backup_name"
    mkdir -p "$backup_subdir"

    # Create backup metadata
    cat > "$backup_subdir/metadata.txt" <<EOF
Backup Created: $(date)
Username: $username
Domain: $domain
Backup Name: $backup_name
EOF

    local backed_up_files=()

    # Find and backup all config files
    local configs
    configs=$(find_all_php_configs "$username" "$domain")

    while IFS= read -r config; do
        [ -z "$config" ] && continue
        [ ! -f "$config" ] && continue

        local backup_path
        backup_path=$(backup_php_config "$config" "$backup_name")

        if [ $? -eq 0 ]; then
            backed_up_files+=("$config")
            echo "Files backed up:" >> "$backup_subdir/metadata.txt"
            echo "  $config → $backup_path" >> "$backup_subdir/metadata.txt"
        fi
    done <<< "$configs"

    # Backup FPM pool config
    local pool_config
    pool_config=$(find_fpm_pool_config "$username" "$domain")

    if [ -n "$pool_config" ] && [ -f "$pool_config" ]; then
        local backup_path
        backup_path=$(backup_php_config "$pool_config" "$backup_name")

        if [ $? -eq 0 ]; then
            backed_up_files+=("$pool_config")
            echo "  $pool_config → $backup_path" >> "$backup_subdir/metadata.txt"
        fi
    fi

    # Return backup location
    if [ ${#backed_up_files[@]} -gt 0 ]; then
        echo "$backup_subdir"
        return 0
    else
        echo "ERROR: No files backed up"
        return 1
    fi
}

# List all backups
# Usage: list_backups
list_backups() {
    if [ ! -d "$BACKUP_DIR" ]; then
        echo "No backups found"
        return 1
    fi

    local backups
    backups=$(find "$BACKUP_DIR" -mindepth 1 -maxdepth 1 -type d -name "2*" | sort -r)

    if [ -z "$backups" ]; then
        echo "No backups found"
        return 1
    fi

    echo "BACKUP_NAME|DATE|USERNAME|DOMAIN|FILE_COUNT"

    while IFS= read -r backup_dir; do
        local backup_name=$(basename "$backup_dir")
        local metadata_file="$backup_dir/metadata.txt"

        if [ -f "$metadata_file" ]; then
            local created=$(grep "^Backup Created:" -- "$metadata_file" | cut -d: -f2- | xargs)
            local username=$(grep "^Username:" -- "$metadata_file" | cut -d: -f2 | xargs)
            local domain=$(grep "^Domain:" -- "$metadata_file" | cut -d: -f2 | xargs)
            local file_count=$(find "$backup_dir" -type f ! -name "metadata.txt" | wc -l)

            echo "$backup_name|$created|$username|$domain|$file_count"
        else
            local file_count=$(find "$backup_dir" -type f | wc -l)
            echo "$backup_name|Unknown|Unknown|Unknown|$file_count"
        fi
    done <<< "$backups"
}

# ============================================================================
# RESTORE FUNCTIONS
# ============================================================================

# Restore a single configuration file
# Usage: restore_php_config <backup_path> <original_path>
restore_php_config() {
    local backup_path="$1"
    local original_path="$2"

    if [ ! -f "$backup_path" ]; then
        echo "ERROR: Backup file not found: $backup_path"
        return 1
    fi

    # Create directory if needed
    local original_dir=$(dirname "$original_path")
    mkdir -p "$original_dir"

    # Restore with metadata preservation
    cp -p "$backup_path" "$original_path"

    if [ $? -eq 0 ]; then
        echo "Restored: $original_path"
        return 0
    else
        echo "ERROR: Failed to restore $original_path"
        return 1
    fi
}

# Restore from backup
# Usage: restore_from_backup <backup_name>
restore_from_backup() {
    local backup_name="$1"
    local backup_dir="$BACKUP_DIR/$backup_name"

    if [ ! -d "$backup_dir" ]; then
        echo "ERROR: Backup not found: $backup_name"
        return 1
    fi

    # Read metadata
    local metadata_file="$backup_dir/metadata.txt"

    if [ ! -f "$metadata_file" ]; then
        echo "ERROR: Backup metadata not found"
        return 1
    fi

    echo "Restoring from backup: $backup_name"
    cat "$metadata_file"
    echo ""

    # Find all backed up files (excluding metadata)
    local restored_count=0
    local failed_count=0

    while IFS= read -r backup_file; do
        # Extract original path from backup structure
        local relative_path="${backup_file#$backup_dir/}"
        local original_path="/$relative_path"

        if restore_php_config "$backup_file" "$original_path"; then
            restored_count=$((restored_count + 1))
        else
            failed_count=$((failed_count + 1))
        fi
    done < <(find "$backup_dir" -type f ! -name "metadata.txt")

    echo ""
    echo "Restore complete: $restored_count files restored, $failed_count failed"

    if [ "$failed_count" -eq 0 ]; then
        return 0
    else
        return 1
    fi
}

# Delete a backup
# Usage: delete_backup <backup_name>
delete_backup() {
    local backup_name="$1"
    local backup_dir="$BACKUP_DIR/$backup_name"

    if [ ! -d "$backup_dir" ]; then
        echo "ERROR: Backup not found: $backup_name"
        return 1
    fi

    rm -rf "$backup_dir"

    if [ $? -eq 0 ]; then
        echo "Backup deleted: $backup_name"
        return 0
    else
        echo "ERROR: Failed to delete backup"
        return 1
    fi
}

# ============================================================================
# CONFIGURATION MODIFICATION FUNCTIONS
# ============================================================================

# Modify a PHP-FPM pool setting
# Usage: modify_fpm_pool_setting <pool_config_file> <setting> <value>
modify_fpm_pool_setting() {
    local pool_config="$1"
    local setting="$2"
    local value="$3"

    if [ ! -f "$pool_config" ]; then
        echo "ERROR: Pool config not found: $pool_config"
        return 1
    fi

    # Escape setting and value for sed (handle special chars like dots)
    local setting_escaped=$(printf '%s\n' "$setting" | sed -e 's/[\.&|/\]/\\&/g')
    local value_escaped=$(printf '%s\n' "$value" | sed -e 's/[\.&|/\]/\\&/g')

    # Check if setting exists (with proper escaping for regex)
    local setting_regex=$(printf '%s\n' "$setting" | sed -e 's/[\.&|/\[^$*]/\\&/g')
    if grep -q "^${setting_regex}\s*=" "$pool_config"; then
        # Replace existing value
        sed -i "s|^${setting_escaped}\s*=.*|${setting} = ${value}|" "$pool_config"
    elif grep -q "^;${setting_regex}\s*=" "$pool_config"; then
        # Uncomment and set value
        sed -i "s|^;${setting_escaped}\s*=.*|${setting} = ${value}|" "$pool_config"
    else
        # Add new setting at end of file
        echo "${setting} = ${value}" >> "$pool_config"
    fi

    if [ $? -eq 0 ]; then
        echo "Modified: $setting = $value in $pool_config"
        return 0
    else
        echo "ERROR: Failed to modify $setting"
        return 1
    fi
}

# Modify a php.ini setting
# Usage: modify_php_ini_setting <php_ini_file> <setting> <value>
modify_php_ini_setting() {
    local php_ini="$1"
    local setting="$2"
    local value="$3"

    if [ ! -f "$php_ini" ]; then
        echo "ERROR: php.ini not found: $php_ini"
        return 1
    fi

    # Escape setting and value for sed (handle special chars like dots)
    local setting_escaped=$(printf '%s\n' "$setting" | sed -e 's/[\.&|/\]/\\&/g')
    local value_escaped=$(printf '%s\n' "$value" | sed -e 's/[\.&|/\]/\\&/g')

    # Check if setting exists (with proper escaping for regex)
    local setting_regex=$(printf '%s\n' "$setting" | sed -e 's/[\.&|/\[^$*]/\\&/g')
    if grep -q "^${setting_regex}\s*=" "$php_ini"; then
        # Replace existing value
        sed -i "s|^${setting_escaped}\s*=.*|${setting} = ${value}|" "$php_ini"
    elif grep -q "^;${setting_regex}\s*=" "$php_ini"; then
        # Uncomment and set value
        sed -i "s|^;${setting_escaped}\s*=.*|${setting} = ${value}|" "$php_ini"
    else
        # Add new setting at end of file
        echo "${setting} = ${value}" >> "$php_ini"
    fi

    if [ $? -eq 0 ]; then
        echo "Modified: $setting = $value in $php_ini"
        return 0
    else
        echo "ERROR: Failed to modify $setting"
        return 1
    fi
}

# Apply multiple FPM pool settings
# Usage: apply_fpm_pool_settings <pool_config_file> <settings_array>
# settings_array format: "setting1=value1" "setting2=value2" ...
apply_fpm_pool_settings() {
    local pool_config="$1"
    shift
    local settings=("$@")

    local success_count=0
    local failed_count=0

    for setting_value in "${settings[@]}"; do
        local setting="${setting_value%%=*}"
        local value="${setting_value#*=}"

        if modify_fpm_pool_setting "$pool_config" "$setting" "$value"; then
            success_count=$((success_count + 1))
        else
            failed_count=$((failed_count + 1))
        fi
    done

    echo "Applied: $success_count settings, $failed_count failed"

    if [ "$failed_count" -eq 0 ]; then
        return 0
    else
        return 1
    fi
}

# ============================================================================
# PHP-FPM RESTART FUNCTIONS
# ============================================================================

# Restart PHP-FPM service
# Usage: restart_php_fpm <php_version>
restart_php_fpm() {
    local php_version="$1"  # e.g., "ea-php82" or "82"

    # Normalize version format
    if [[ ! "$php_version" =~ ^ea-php ]]; then
        php_version="ea-php${php_version}"
    fi

    # Detect init system
    if command -v systemctl >/dev/null 2>&1; then
        # systemd
        local service_name="${php_version}-php-fpm"

        systemctl restart "$service_name" 2>/dev/null

        if [ $? -eq 0 ]; then
            echo "Restarted: $service_name (systemd)"
            return 0
        else
            echo "ERROR: Failed to restart $service_name"
            return 1
        fi
    elif command -v service >/dev/null 2>&1; then
        # sysvinit
        local service_name="${php_version}-php-fpm"

        service "$service_name" restart 2>/dev/null

        if [ $? -eq 0 ]; then
            echo "Restarted: $service_name (service)"
            return 0
        else
            echo "ERROR: Failed to restart $service_name"
            return 1
        fi
    else
        echo "ERROR: Cannot detect init system"
        return 1
    fi
}

# Reload PHP-FPM service (graceful restart)
# Usage: reload_php_fpm <php_version>
reload_php_fpm() {
    local php_version="$1"

    # Normalize version format
    if [[ ! "$php_version" =~ ^ea-php ]]; then
        php_version="ea-php${php_version}"
    fi

    # Detect init system
    if command -v systemctl >/dev/null 2>&1; then
        # systemd
        local service_name="${php_version}-php-fpm"

        systemctl reload "$service_name" 2>/dev/null

        if [ $? -eq 0 ]; then
            echo "Reloaded: $service_name (graceful)"
            return 0
        else
            # Fallback to restart if reload fails
            restart_php_fpm "$php_version"
            return $?
        fi
    else
        # Reload not supported, use restart
        restart_php_fpm "$php_version"
        return $?
    fi
}

# Verify PHP-FPM is running
# Usage: verify_php_fpm_running <php_version>
verify_php_fpm_running() {
    local php_version="$1"

    # Normalize version format
    if [[ ! "$php_version" =~ ^ea-php ]]; then
        php_version="ea-php${php_version}"
    fi

    if command -v systemctl >/dev/null 2>&1; then
        local service_name="${php_version}-php-fpm"

        systemctl is-active "$service_name" >/dev/null 2>&1

        if [ $? -eq 0 ]; then
            echo "Running: $service_name"
            return 0
        else
            echo "NOT running: $service_name"
            return 1
        fi
    else
        # Check process
        if pgrep -f "${php_version}-php-fpm" >/dev/null 2>&1; then
            echo "Running: ${php_version}-php-fpm"
            return 0
        else
            echo "NOT running: ${php_version}-php-fpm"
            return 1
        fi
    fi
}

# Export all functions
export -f initialize_backup_system
export -f backup_php_config
export -f backup_fpm_pool
export -f backup_user_php_configs
export -f list_backups
export -f restore_php_config
export -f restore_from_backup
export -f delete_backup
export -f modify_fpm_pool_setting
export -f modify_php_ini_setting
export -f apply_fpm_pool_settings
export -f restart_php_fpm
export -f reload_php_fpm
export -f verify_php_fpm_running
