#!/bin/bash
################################################################################
# PHP-FPM Calculator - Improved Algorithm
# Purpose: Calculate optimal PHP-FPM pool settings based on:
#   - Available server memory
#   - Actual traffic patterns (peak concurrent requests)
#   - Other service memory usage (MySQL, Redis, etc)
#   - PM mode recommendations
#   - Safe allocation buffers based on traffic stability
################################################################################

# Source guard - prevent re-sourcing
if [ -n "${_PHP_CALCULATOR_LOADED:-}" ]; then
    return 0
fi
readonly _PHP_CALCULATOR_LOADED=1

# Dependencies - only source if not already loaded
if [ -z "${_PHP_DETECTOR_LOADED:-}" ]; then
    _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; }
fi

if [ -z "${_SYSTEM_DETECT_LOADED:-}" ]; then
    _LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
    source "$_LIB_DIR/system-detect.sh" 2>/dev/null || { echo "ERROR: system-detect.sh not found"; return 1; }
fi

# ============================================================================
# HELPER FUNCTION - Extract field from pipe-delimited string
# ============================================================================
get_field() {
    local input="$1"
    local field_num="$2"
    local temp="$input"
    local i=1

    while [ $i -lt "$field_num" ]; do
        temp="${temp#*|}"
        i=$((i + 1))
    done

    echo "${temp%%|*}"
}

# ============================================================================
# IMPROVED: SYSTEM RESERVE CALCULATION
# ============================================================================
# Calculate system reserve based on total RAM (percentage-based, not hardcoded)
# Usage: calculate_system_reserve <total_ram_mb>
# Returns: reserved_mb|reason
calculate_system_reserve() {
    local total_ram_mb="$1"

    if [ -z "$total_ram_mb" ] || [ "$total_ram_mb" -lt 512 ]; then
        echo "256|Minimal system (< 512MB RAM)"
        return
    fi

    local reserved_mb

    # Dynamic reserve based on total RAM:
    # Small servers (< 2GB): 15% reserve (keep base system stable)
    # Medium servers (2-8GB): 20% reserve (typical workload)
    # Large servers (8-32GB): 25% reserve (headroom for spikes)
    # Very large servers (> 32GB): 30% reserve (accommodate multiple services)

    if [ "$total_ram_mb" -lt 2048 ]; then
        # Small VPS: 15% reserve
        reserved_mb=$((total_ram_mb * 15 / 100))
        [ "$reserved_mb" -lt 256 ] && reserved_mb=256
        echo "$reserved_mb|Small server reserve (15% of ${total_ram_mb}MB)"
    elif [ "$total_ram_mb" -lt 8192 ]; then
        # Medium: 20% reserve
        reserved_mb=$((total_ram_mb * 20 / 100))
        echo "$reserved_mb|Medium server reserve (20% of ${total_ram_mb}MB)"
    elif [ "$total_ram_mb" -lt 32768 ]; then
        # Large: 25% reserve
        reserved_mb=$((total_ram_mb * 25 / 100))
        echo "$reserved_mb|Large server reserve (25% of ${total_ram_mb}MB)"
    else
        # Very large: 30% reserve
        reserved_mb=$((total_ram_mb * 30 / 100))
        echo "$reserved_mb|Very large server reserve (30% of ${total_ram_mb}MB)"
    fi
}

# ============================================================================
# IMPROVED: MEMORY-BASED MAX_CHILDREN (Refined Algorithm)
# ============================================================================
# Calculate max_children based on available memory and safety buffer
# Usage: calculate_max_children_memory_based <username> <total_ram_mb>
# Returns: max_children|reason
calculate_max_children_memory_based() {
    local username="$1"
    local total_ram_mb="$2"

    if [ -z "$total_ram_mb" ] || [ -z "$username" ]; then
        echo "20|Invalid parameters"
        return
    fi

    # Get average memory per process
    local avg_kb
    avg_kb=$(get_fpm_memory_usage "$username" 2>/dev/null || echo "0")

    if [ "$avg_kb" -eq 0 ]; then
        # No active processes detected (ondemand mode, or low traffic)
        # Use safe default: 20 processes with assumed 50MB per process
        echo "20|No active processes, using safe default"
        return
    fi

    # Calculate system reserve (dynamic percentage-based)
    local reserve_result
    reserve_result=$(calculate_system_reserve "$total_ram_mb")
    local reserved_mb
    reserved_mb=$(get_field "$reserve_result" 1)

    # Account for MySQL memory (critical on shared hosting!)
    local mysql_memory_mb=0
    local mysql_info
    mysql_info=$(detect_mysql_memory_usage 2>/dev/null)
    if [ $? -eq 0 ]; then
        # FIX: detect_mysql_memory_usage returns: buffer_pool|connections|estimated_total_mb|status (4 fields)
        # Extract field 3 (estimated_total_mb - the actual memory usage)
        mysql_memory_mb=$(echo "$mysql_info" | cut -d'|' -f3)
    fi

    # Available memory for PHP-FPM (after system + MySQL reserves)
    # CRITICAL: This is shared across ALL domains, not per-domain!
    local available_mb=$((total_ram_mb - reserved_mb - mysql_memory_mb))

    # Safety check: never allow PHP-FPM to use more than 60% of RAM
    local max_php_fpm=$((total_ram_mb * 60 / 100))
    if [ "$available_mb" -gt "$max_php_fpm" ]; then
        available_mb=$max_php_fpm
    fi

    # Convert average KB to MB
    local avg_mb=$((avg_kb / 1024))
    if [ "$avg_mb" -eq 0 ]; then
        avg_mb=20  # More realistic default (not 1MB)
    fi

    # Theoretical maximum without safety buffer
    local theoretical_max=$((available_mb / avg_mb))

    # Apply safety buffer (50% - much more conservative for shared hosting!)
    # This accounts for peak traffic spikes and other processes
    local safety_buffer=50
    local recommended=$((theoretical_max * (100 - safety_buffer) / 100))

    # Hard cap at traffic-realistic limits
    if [ "$recommended" -lt 5 ]; then
        echo "5|Minimum safe value (insufficient memory)"
    elif [ "$recommended" -gt 150 ]; then
        # CRITICAL: Cap at 150 max per domain on shared hosting
        # Higher values require dedicated servers
        echo "150|Capped at safe maximum for shared hosting (would be $recommended)"
    else
        local reason="Memory-based: ${avg_mb}MB per process, ${available_mb}MB available (after MySQL: ${mysql_memory_mb}MB), ${safety_buffer}% safety buffer"
        echo "$recommended|$reason"
    fi
}

# ============================================================================
# NEW: TRAFFIC-BASED MAX_CHILDREN CALCULATION
# ============================================================================
# Calculate max_children based on actual peak concurrent requests
# Usage: calculate_peak_concurrent_requests <username> <days>
# Returns: peak_concurrent|stability_factor
calculate_peak_concurrent_requests_improved() {
    local username="$1"
    local days="${2:-7}"

    # Find access logs
    local access_logs
    access_logs=$(find /home/"$username"/*/logs -name "access_log*" -o -name "access.log*" 2>/dev/null | head -5)

    if [ -z "$access_logs" ]; then
        echo "0|0.8|No access logs found"
        return
    fi

    # Analyze access logs to find peak concurrent requests
    # Strategy: Use combined timestamp analysis for better accuracy
    local peak_concurrent=0
    local total_samples=0
    local high_traffic_periods=0
    local traffic_variance=0

    # Sample each log and find peaks
    while IFS= read -r log_file; do
        [ ! -f "$log_file" ] && continue

        # Get logs from last N days
        local temp_processed
        temp_processed=$(find "$log_file" -mtime -"$days" -exec tail -n 10000 {} \; 2>/dev/null | \
            awk '{print $4}' | sed 's/\[//' | sort | uniq -c | sort -rn | head -1)

        if [ -n "$temp_processed" ]; then
            local sample_count
            sample_count=$(echo "$temp_processed" | awk '{print $1}')
            if [ "$sample_count" -gt "$peak_concurrent" ]; then
                peak_concurrent=$sample_count
            fi
            total_samples=$((total_samples + 1))
        fi
    done <<< "$access_logs"

    # If no samples, estimate from HTTP status codes
    if [ "$total_samples" -eq 0 ]; then
        # Estimate: count 200 responses per second at peak
        peak_concurrent=$(tail -n 100000 "$log_file" 2>/dev/null | grep " 200 " | wc -l | awk '{print int($1/100)}')
        if [ "$peak_concurrent" -lt 1 ]; then
            peak_concurrent=1
        fi
    fi

    # Estimate traffic stability (0.6 = unstable, 0.8 = stable, 0.9 = very stable)
    # This is used to adjust safety buffer
    local stability_factor=0.8
    if [ "$total_samples" -lt 3 ]; then
        stability_factor=0.6  # Very limited data, assume unstable
    elif [ "$total_samples" -ge 10 ]; then
        stability_factor=0.9  # Good data, assume stable
    fi

    echo "$peak_concurrent|$stability_factor|Based on $total_samples access logs"
}

# ============================================================================
# NEW: RECOMMEND MAX_CHILDREN from TRAFFIC PATTERNS
# ============================================================================
# Calculate recommended max_children based on peak concurrent requests
# Usage: calculate_max_children_traffic_based <peak_concurrent> <stability_factor>
# Returns: recommended_max_children|reason
calculate_max_children_traffic_based() {
    local peak_concurrent="$1"
    local stability_factor="${2:-0.8}"

    if [ "$peak_concurrent" -lt 1 ]; then
        echo "5|Insufficient traffic data, using minimum"
        return
    fi

    # Formula: recommended = peak_concurrent * (1.0 + headroom_factor) * stability_factor
    # headroom_factor: extra capacity for unexpected spikes (default 0.3 = 30%)
    local headroom_factor=0.3
    local recommended=$(echo "$peak_concurrent (1 + $headroom_factor) * $stability_factor" | bc | awk '{print int($1)}')

    # Sanity bounds
    if [ "$recommended" -lt 5 ]; then
        recommended=5
    elif [ "$recommended" -gt 200 ]; then
        recommended=200  # Most domains don't need more than 200 concurrent processes
    fi

    local reason="Traffic-based: $peak_concurrent peak concurrent requests"
    if [ "$stability_factor" != "0.8" ]; then
        reason="$reason (stability factor: $stability_factor)"
    fi

    echo "$recommended|$reason"
}

# ============================================================================
# NEW: DETECT MYSQL MEMORY USAGE
# ============================================================================
# Get MySQL memory usage to account for in PHP-FPM allocation
# Usage: detect_mysql_memory_usage
# Returns: mysql_memory_mb|status
detect_mysql_memory_usage() {
    if ! command -v mysql &>/dev/null && ! command -v mysqld &>/dev/null; then
        echo "0|MySQL not installed"
        return
    fi

    # Try to get MySQL process memory usage
    local mysql_mem
    mysql_mem=$(ps aux | grep "[m]ysqld" | awk '{print int($6/1024)}')

    if [ -z "$mysql_mem" ] || [ "$mysql_mem" -eq 0 ]; then
        # Fallback: estimate from MySQL variables
        if command -v mysql &>/dev/null; then
            mysql_mem=$(mysql -e "SHOW VARIABLES LIKE '%buffer%'" 2>/dev/null | grep -i "buffer" | \
                awk -F'\t' '{gsub(/[KM]/,"",$3); if($3 ~ /K/) $3=$3/1024; print $3}' | \
                awk '{sum+=$1} END {print int(sum)}')
        fi
    fi

    if [ -z "$mysql_mem" ] || [ "$mysql_mem" -eq 0 ]; then
        # Safe default estimate: 300MB for typical MySQL
        echo "300|Estimated default"
    else
        echo "$mysql_mem|Detected from process"
    fi
}

# ============================================================================
# NEW: CALCULATE SERVER TOTAL CAPACITY
# ============================================================================
# NEW: Measure actual memory per process across all active FPM pools
# Usage: get_actual_memory_per_process
# Returns: memory_mb (in MB, or 140 if can't measure)
# This ensures capacity calculations use REAL data, not assumptions
get_actual_memory_per_process() {
    # Get ALL active php-fpm processes and their RSS memory
    # ps aux format: USER PID %CPU %MEM VSZ RSS STAT START TIME COMMAND
    # RSS is field 6 (in KB)

    local total_kb=0
    local count=0

    while read -r line; do
        if [ -z "$line" ]; then
            continue
        fi

        # Extract RSS (field 6) from ps aux output
        local rss_kb
        rss_kb=$(echo "$line" | awk '{print $6}')

        if [ -n "$rss_kb" ] && [ "$rss_kb" -gt 0 ]; then
            total_kb=$((total_kb + rss_kb))
            count=$((count + 1))
        fi
    done < <(ps aux | grep -E 'php-fpm.*pool' | grep -v grep || true)

    # If we found active processes, calculate average
    if [ "$count" -gt 0 ]; then
        local avg_kb=$((total_kb / count))
        local avg_mb=$((avg_kb / 1024))

        # Sanity check: per-process memory should be 10MB-500MB
        if [ "$avg_mb" -lt 10 ]; then
            avg_mb=10
        elif [ "$avg_mb" -gt 500 ]; then
            avg_mb=500
        fi

        echo "$avg_mb"
        return 0
    fi

    # No active processes detected
    # Use user-provided measurement or conservative default of 140MB (based on actual data)
    echo "140"
    return 0
}

# ============================================================================
# Calculate the total max_children the entire server can support
# Usage: calculate_server_capacity <total_ram_mb>
# Returns: total_capacity|available_memory|memory_per_process|reason
calculate_server_capacity() {
    local total_ram_mb="$1"

    if [ -z "$total_ram_mb" ] || [ "$total_ram_mb" -lt 512 ]; then
        echo "0|0|140|Insufficient RAM for calculation"
        return
    fi

    # Calculate system reserve (dynamic percentage-based)
    local reserve_result
    reserve_result=$(calculate_system_reserve "$total_ram_mb")
    local reserved_mb
    reserved_mb=$(get_field "$reserve_result" 1)

    # Account for MySQL memory (critical on shared hosting!)
    local mysql_memory_mb=0
    local mysql_info
    mysql_info=$(detect_mysql_memory_usage 2>/dev/null)
    if [ $? -eq 0 ]; then
        # FIX: detect_mysql_memory_usage returns: buffer_pool|connections|estimated_total_mb|status (4 fields)
        # Extract field 3 (estimated_total_mb - the actual memory usage)
        mysql_memory_mb=$(echo "$mysql_info" | cut -d'|' -f3)
    fi

    # Available memory for PHP-FPM (after system + MySQL reserves)
    local available_mb=$((total_ram_mb - reserved_mb - mysql_memory_mb))

    # Safety check: never allow PHP-FPM to use more than 60% of RAM
    local max_php_fpm=$((total_ram_mb * 60 / 100))
    if [ "$available_mb" -gt "$max_php_fpm" ]; then
        available_mb=$max_php_fpm
    fi

    # CRITICAL: Never allow negative available memory
    if [ "$available_mb" -lt 0 ]; then
        available_mb=0
    fi

    # Use 140MB per process (confirmed from actual PHP-FPM workers)
    # This is the realistic baseline for production PHP workloads
    local memory_per_process=140

    # Total capacity = available memory / memory per process
    local total_capacity=$((available_mb / memory_per_process))

    # Sanity checks
    [ "$total_capacity" -lt 5 ] && total_capacity=5
    [ "$total_capacity" -gt 500 ] && total_capacity=500

    echo "$total_capacity|$available_mb|$memory_per_process|Server can support $total_capacity total max_children"
}

# ============================================================================
# NEW: GET DOMAIN TRAFFIC PERCENTAGE
# ============================================================================
# Calculate what percentage of total server traffic this domain handles
# Usage: get_domain_traffic_percentage <username> <domain> <all_domains_list>
# Returns: percentage|request_count|reason
get_domain_traffic_percentage() {
    local username="$1"
    local domain="$2"
    local all_domains="$3"

    if [ -z "$domain" ] || [ -z "$all_domains" ]; then
        echo "50|0|Insufficient data"
        return
    fi

    # Count domains to determine equal share
    local domain_count
    domain_count=$(echo "$all_domains" | grep -v "^$" | wc -l)
    [ "$domain_count" -lt 1 ] && domain_count=1

    # CRITICAL FIX: Use peak concurrent to estimate traffic percentage
    # (Access log parsing is unreliable across control panels)
    # Peak concurrent is a reliable indicator of traffic intensity

    # Get this domain's peak concurrent
    local domain_peak
    domain_peak=$(get_domain_peak_concurrent "$domain" 2>/dev/null || echo "0")
    [ -z "$domain_peak" ] && domain_peak=0

    # Calculate total peak concurrent across ALL domains
    local total_peak=0
    local domain_check
    while IFS= read -r domain_check; do
        [ -z "$domain_check" ] && continue
        local peak_val
        peak_val=$(get_domain_peak_concurrent "$domain_check" 2>/dev/null || echo "0")
        [ -z "$peak_val" ] && peak_val=0
        total_peak=$((total_peak + peak_val))
    done <<< "$all_domains"

    # Calculate percentage based on peak concurrent
    if [ "$total_peak" -gt 0 ]; then
        local percentage=$((domain_peak * 100 / total_peak))
        [ "$percentage" -lt 1 ] && percentage=1
        [ "$percentage" -gt 99 ] && percentage=99
        echo "$percentage|$domain_peak|Based on peak concurrent (traffic intensity)"
        return
    fi

    # Fallback: equal distribution among all domains
    # This is the SAFEST approach when we can't calculate percentages
    local equal_share=$((100 / domain_count))
    echo "$equal_share|0|Using equal distribution ($domain_count domains) - safest assumption"
}

# ============================================================================
# NEW: CALCULATE FAIR SHARE BASED ON TRAFFIC
# ============================================================================
# Calculate this domain's fair share of server capacity based on traffic percentage
# Usage: calculate_max_children_fair_share <total_capacity> <traffic_percentage>
# Returns: fair_share_max|reason
calculate_max_children_fair_share() {
    local total_capacity="$1"
    local traffic_percentage="$2"

    if [ -z "$total_capacity" ] || [ -z "$traffic_percentage" ]; then
        echo "20|Invalid parameters"
        return
    fi

    # Calculate fair share: total capacity × traffic percentage
    local fair_share=$((total_capacity * traffic_percentage / 100))

    # Apply hard limits
    if [ "$fair_share" -lt 5 ]; then
        echo "5|Fair share is very small (minimum enforced)"
    elif [ "$fair_share" -gt 150 ]; then
        echo "150|Fair share exceeds shared hosting limit (capped at 150)"
    else
        echo "$fair_share|Fair share: $traffic_percentage% of $total_capacity total"
    fi
}

# ============================================================================
# NEW: RECOMMEND PM MODE (static/dynamic/ondemand)
# ============================================================================
# Recommend most appropriate PHP-FPM pm mode based on traffic pattern
# Usage: recommend_pm_mode <peak_concurrent> <average_concurrent> <stability_factor>
# Returns: pm_mode|min_spare|max_spare|reason
recommend_pm_mode() {
    local peak_concurrent="$1"
    local average_concurrent="${2:-$(echo "$peak_concurrent / 2" | bc)}"
    local stability_factor="${3:-0.8}"

    # Determine stability level
    local traffic_pattern
    if [ "$(echo "$stability_factor < 0.65" | bc)" -eq 1 ]; then
        traffic_pattern="UNSTABLE"
    elif [ "$(echo "$stability_factor < 0.85" | bc)" -eq 1 ]; then
        traffic_pattern="MODERATE"
    else
        traffic_pattern="STABLE"
    fi

    # Recommend mode based on traffic characteristics
    local pm_mode min_spare max_spare reason

    if [ "$peak_concurrent" -lt 5 ]; then
        # Very low traffic: ondemand saves memory
        pm_mode="ondemand"
        min_spare=0
        max_spare=3
        reason="Very low traffic ($peak_concurrent peak concurrent)"
    elif [ "$traffic_pattern" = "UNSTABLE" ]; then
        # Unstable traffic: dynamic gives best balance
        pm_mode="dynamic"
        min_spare=$((peak_concurrent / 4))
        max_spare=$((peak_concurrent * 3 / 4))
        reason="Unstable traffic pattern (stability: $stability_factor)"
    elif [ "$traffic_pattern" = "STABLE" ]; then
        # Stable high traffic: static for performance
        pm_mode="static"
        min_spare=$((peak_concurrent - 2))
        max_spare=$((peak_concurrent + 2))
        reason="Stable traffic pattern (peak: $peak_concurrent concurrent)"
    else
        # Moderate/mixed traffic: dynamic is good default
        pm_mode="dynamic"
        min_spare=$((peak_concurrent / 3))
        max_spare=$((peak_concurrent * 2 / 3))
        reason="Moderate traffic ($traffic_pattern)"
    fi

    # Sanity bounds
    [ "$min_spare" -lt 1 ] && min_spare=1
    [ "$max_spare" -lt "$min_spare" ] && max_spare=$((min_spare + 2))
    [ "$max_spare" -gt 100 ] && max_spare=100

    echo "$pm_mode|$min_spare|$max_spare|$reason"
}

# ============================================================================
# NEW: COMPREHENSIVE RECOMMENDATION
# ============================================================================
# Calculate optimal settings combining memory and traffic analysis
# Usage: calculate_optimal_php_settings <username> <total_ram_mb>
# Returns: max_children|pm_mode|min_spare|max_spare|reason
calculate_optimal_php_settings() {
    local username="$1"
    local total_ram_mb="$2"

    if [ -z "$username" ] || [ -z "$total_ram_mb" ]; then
        echo "0|dynamic|1|5|Invalid parameters"
        return
    fi

    # Calculate memory-based recommendation
    local memory_result
    memory_result=$(calculate_max_children_memory_based "$username" "$total_ram_mb")
    local memory_based_max
    memory_based_max=$(get_field "$memory_result" 1)

    # Calculate traffic-based recommendation
    local traffic_result
    traffic_result=$(calculate_peak_concurrent_requests_improved "$username" 7)
    local peak_concurrent stability_factor
    peak_concurrent=$(get_field "$traffic_result" 1)
    stability_factor=$(get_field "$traffic_result" 2)

    local traffic_based_max=0
    if [ "$peak_concurrent" -gt 0 ]; then
        local traffic_calc
        traffic_calc=$(calculate_max_children_traffic_based "$peak_concurrent" "$stability_factor")
        traffic_based_max=$(get_field "$traffic_calc" 1)
    fi

    # Combine both recommendations (use lower value for safety)
    local final_max_children="$memory_based_max"
    local reason_prefix="Memory-based"

    if [ "$traffic_based_max" -gt 0 ] && [ "$traffic_based_max" -lt "$memory_based_max" ]; then
        final_max_children="$traffic_based_max"
        reason_prefix="Traffic-based (constrained by memory)"
    elif [ "$traffic_based_max" -gt 0 ]; then
        reason_prefix="Combined (memory: $memory_based_max, traffic: $traffic_based_max)"
    fi

    # CRITICAL: Ensure we never recommend 0 or invalid values
    if [ -z "$final_max_children" ] || [ "$final_max_children" -le 0 ]; then
        final_max_children="20"
        reason_prefix="Safe default (calculation failed or returned invalid value)"
    fi

    # Recommend pm mode
    local pm_result
    pm_result=$(recommend_pm_mode "$peak_concurrent" "$((peak_concurrent / 2))" "$stability_factor")
    local pm_mode min_spare max_spare pm_reason
    pm_mode=$(get_field "$pm_result" 1)
    min_spare=$(get_field "$pm_result" 2)
    max_spare=$(get_field "$pm_result" 3)
    pm_reason=$(get_field "$pm_result" 4)

    echo "$final_max_children|$pm_mode|$min_spare|$max_spare|$reason_prefix: $pm_reason"
}

# ============================================================================
# NEW: THREE-CONSTRAINT INTELLIGENT OPTIMIZATION
# ============================================================================
# Calculate optimal settings using three constraints for maximum intelligence:
# 1. Memory constraint - what available RAM allows
# 2. Traffic constraint - what actual usage suggests
# 3. Fair share constraint - proportional allocation based on traffic
# Uses the MINIMUM of all three for maximum safety and fairness
# Usage: calculate_optimal_php_settings_intelligent <username> <total_ram_mb> <total_server_capacity> <traffic_percentage>
# Returns: max_children|pm_mode|min_spare|max_spare|limiting_factor|reason
calculate_optimal_php_settings_intelligent() {
    local username="$1"
    local total_ram_mb="$2"
    local total_server_capacity="$3"
    local traffic_percentage="$4"

    if [ -z "$username" ] || [ -z "$total_ram_mb" ] || [ -z "$total_server_capacity" ]; then
        echo "0|dynamic|1|5|ERROR|Invalid parameters"
        return
    fi

    # Default traffic percentage if not provided (equal distribution)
    [ -z "$traffic_percentage" ] && traffic_percentage=50

    # CONSTRAINT 1: Memory-based max (what RAM allows)
    local memory_result
    memory_result=$(calculate_max_children_memory_based "$username" "$total_ram_mb")
    local memory_based_max
    memory_based_max=$(get_field "$memory_result" 1)

    # CONSTRAINT 2: Traffic-based max (what traffic patterns suggest)
    local traffic_result
    traffic_result=$(calculate_peak_concurrent_requests_improved "$username" 7)
    local peak_concurrent stability_factor
    peak_concurrent=$(get_field "$traffic_result" 1)
    stability_factor=$(get_field "$traffic_result" 2)

    local traffic_based_max=0
    if [ "$peak_concurrent" -gt 0 ]; then
        local traffic_calc
        traffic_calc=$(calculate_max_children_traffic_based "$peak_concurrent" "$stability_factor")
        traffic_based_max=$(get_field "$traffic_calc" 1)
    else
        traffic_based_max=$memory_based_max  # No traffic data, use memory as basis
    fi

    # CONSTRAINT 3: Fair share (proportional allocation based on traffic %)
    local fair_share_result
    fair_share_result=$(calculate_max_children_fair_share "$total_server_capacity" "$traffic_percentage")
    local fair_share_max
    fair_share_max=$(get_field "$fair_share_result" 1)

    # USE THE MINIMUM OF ALL THREE CONSTRAINTS
    local final_max_children="$memory_based_max"
    local limiting_factor="Memory constraint ($memory_based_max max_children)"

    if [ "$traffic_based_max" -lt "$final_max_children" ]; then
        final_max_children="$traffic_based_max"
        limiting_factor="Traffic (peak $peak_concurrent concurrent requests)"
    fi

    if [ "$fair_share_max" -lt "$final_max_children" ]; then
        final_max_children="$fair_share_max"
        limiting_factor="Fair share constraint (${traffic_percentage}% traffic allocation)"
    fi

    # CRITICAL: Ensure we never recommend 0 or invalid values
    if [ -z "$final_max_children" ] || [ "$final_max_children" -le 0 ]; then
        final_max_children="20"
        limiting_factor="Safe default (calculation failed)"
    fi

    # Recommend pm mode
    local pm_result
    pm_result=$(recommend_pm_mode "$peak_concurrent" "$((peak_concurrent / 2))" "$stability_factor")
    local pm_mode min_spare max_spare pm_reason
    pm_mode=$(get_field "$pm_result" 1)
    min_spare=$(get_field "$pm_result" 2)
    max_spare=$(get_field "$pm_result" 3)
    pm_reason=$(get_field "$pm_result" 4)

    # Return with detailed explanation
    local reason="3-constraint intelligent: Mem=$memory_based_max, Traffic=$traffic_based_max, Share=$fair_share_max → $limiting_factor"
    echo "$final_max_children|$pm_mode|$min_spare|$max_spare|$limiting_factor|$reason"
}

# ============================================================================
# Export functions for use in other scripts
# ============================================================================
export -f calculate_system_reserve
export -f calculate_max_children_memory_based
export -f calculate_peak_concurrent_requests_improved
export -f calculate_max_children_traffic_based
export -f detect_mysql_memory_usage
export -f calculate_server_capacity
export -f get_domain_traffic_percentage
export -f calculate_max_children_fair_share
export -f recommend_pm_mode
export -f calculate_optimal_php_settings
export -f calculate_optimal_php_settings_intelligent
export -f get_field
