#!/bin/bash
# PHP-FPM Server Scanner Module
# Handles enumeration of accounts/domains across entire server with filtering
# Part of PHP Optimizer - Phase 3 Refactoring
# Ensures full server-wide scanning and action capability

# ============================================================================
# ACCOUNT ENUMERATION FUNCTIONS
# ============================================================================

# Enumerate all accounts/users on the server
enumerate_all_accounts() {
    local force_refresh="${1:-false}"
    local cache_file="/tmp/php-scanner-accounts-cache-$$"

    # Return cached results if available (unless force_refresh=true)
    if [ "$force_refresh" != "true" ] && [ -f "$cache_file" ]; then
        cat "$cache_file"
        return 0
    fi

    # Delegate to user-manager.sh if available
    if type list_all_users >/dev/null 2>&1; then
        local accounts
        accounts=$(list_all_users)
        if [ -n "$accounts" ]; then
            echo "$accounts" | tee "$cache_file"
            return 0
        fi
    fi

    # Fallback enumeration if user-manager.sh not available
    case "${SYS_CONTROL_PANEL:-unknown}" in
        cpanel)
            _enumerate_cpanel_accounts | tee "$cache_file"
            ;;
        plesk)
            _enumerate_plesk_accounts | tee "$cache_file"
            ;;
        interworx)
            _enumerate_interworx_accounts | tee "$cache_file"
            ;;
        *)
            _enumerate_system_accounts | tee "$cache_file"
            ;;
    esac
}

# cPanel account enumeration
_enumerate_cpanel_accounts() {
    local cpanel_users_dir="${SYS_CPANEL_USERS_DIR:-/var/cpanel/users}"
    if [ -d "$cpanel_users_dir" ]; then
        ls "$cpanel_users_dir" 2>/dev/null | grep -v "^system\|^root\|^\." || true
    else
        awk -F: '{print $2}' /etc/trueuserdomains 2>/dev/null | sort -u || true
    fi
}

# Plesk account enumeration
_enumerate_plesk_accounts() {
    if command_exists mysql && [ -f /etc/psa/.psa.shadow ]; then
        mysql -Ns psa -e "SELECT login FROM sys_users WHERE type='user'" 2>/dev/null || true
    else
        find /var/www/vhosts -maxdepth 1 -type d -printf "%f\n" 2>/dev/null | \
            grep -v "^system$\|^default$\|^chroot$\|^\.skel$\|^fs$\|^fs-passwd$\|^\." || true
    fi
}

# InterWorx account enumeration
_enumerate_interworx_accounts() {
    if [ -x "/usr/local/interworx/bin/listaccounts.pex" ]; then
        /usr/local/interworx/bin/listaccounts.pex --output user 2>/dev/null || true
    else
        if [ -d "/etc/httpd/conf.d" ]; then
            grep -h "^[[:space:]]*SuexecUserGroup" /etc/httpd/conf.d/vhost_*.conf 2>/dev/null | \
                awk '{print $2}' | sort -u || true
        else
            find /home -maxdepth 1 -type d ! -name "home" ! -name "interworx" -printf "%f\n" 2>/dev/null | sort
        fi
    fi
}

# System-wide account enumeration (fallback)
_enumerate_system_accounts() {
    awk -F: '($3 >= 500) && ($3 != 65534) {print $1}' /etc/passwd 2>/dev/null | \
        grep -v "^root\|^nobody\|^ntp\|^mysql\|^www-data\|^apache\|^nginx" | \
        sort -u || true
}

# ============================================================================
# DOMAIN ENUMERATION FUNCTIONS
# ============================================================================

# Enumerate all domains for a specific user/account
enumerate_user_domains() {
    [ -z "$1" ] && return 1
    local username="$1"
    local force_refresh="${2:-false}"
    local cache_file="/tmp/php-scanner-domains-${username}-cache-$$"

    # Return cached results if available (unless force_refresh=true)
    if [ "$force_refresh" != "true" ] && [ -f "$cache_file" ]; then
        cat "$cache_file"
        return 0
    fi

    # Delegate to user-manager.sh if available
    if type get_user_domains >/dev/null 2>&1; then
        local domains
        domains=$(get_user_domains "$username")
        if [ -n "$domains" ]; then
            echo "$domains" | tee "$cache_file"
            return 0
        fi
    fi

    # Fallback domain enumeration
    case "${SYS_CONTROL_PANEL:-unknown}" in
        cpanel)
            _enumerate_cpanel_domains "$username" | tee "$cache_file"
            ;;
        plesk)
            _enumerate_plesk_domains "$username" | tee "$cache_file"
            ;;
        interworx)
            _enumerate_interworx_domains "$username" | tee "$cache_file"
            ;;
        *)
            echo ""
            ;;
    esac
}

# cPanel domain enumeration
_enumerate_cpanel_domains() {
    local username="$1"
    [ -z "$username" ] && return 1

    # Primary domain
    grep ": ${username}$" /etc/trueuserdomains 2>/dev/null | cut -d: -f1 || true

    # Addon domains
    if [ -f "/etc/userdatadomains" ]; then
        grep "==${username}$" /etc/userdatadomains 2>/dev/null | cut -d: -f1 || true
    fi
}

# Plesk domain enumeration
_enumerate_plesk_domains() {
    local username="$1"
    [ -z "$username" ] && return 1

    if command_exists mysql && [ -f /etc/psa/.psa.shadow ]; then
        mysql -Ns psa -e "SELECT d.name FROM domains d JOIN sys_users u ON d.id=u.domain_id WHERE u.login='$username'" 2>/dev/null || true
    elif [ -x "/usr/local/psa/bin/plesk" ]; then
        /usr/local/psa/bin/plesk bin site --list 2>/dev/null | grep -i "$username" || true
    elif [ -d "/var/www/vhosts/$username" ]; then
        echo "$username"
    fi
}

# InterWorx domain enumeration
_enumerate_interworx_domains() {
    local username="$1"
    [ -z "$username" ] && return 1

    if [ -x "/usr/local/interworx/bin/listaccounts.pex" ]; then
        /usr/local/interworx/bin/listaccounts.pex 2>/dev/null | \
            awk -v user="$username" '$1 == user {print $2}'
    fi

    if [ -d "/etc/httpd/conf.d" ]; then
        grep -l "SuexecUserGroup ${username}" /etc/httpd/conf.d/vhost_*.conf 2>/dev/null | \
            sed 's|.*/vhost_||; s|\.conf$||' | \
            grep -vF "${username}." 2>/dev/null | \
            sort -u
    fi
}

# Enumerate ALL domains on the server (across all users)
enumerate_all_domains() {
    local force_refresh="${1:-false}"
    local cache_file="/tmp/php-scanner-all-domains-cache-$$"
    local progress_file="/tmp/php-scanner-progress-$$"

    # Return cached results if available (unless force_refresh=true)
    if [ "$force_refresh" != "true" ] && [ -f "$cache_file" ]; then
        cat "$cache_file"
        return 0
    fi

    > "$progress_file"  # Clear progress file
    local users
    local domain_list=""
    local user_count=0
    local current_user=0

    users=$(enumerate_all_accounts)
    user_count=$(echo "$users" | wc -l)

    while IFS= read -r username; do
        [ -z "$username" ] && continue

        current_user=$((current_user + 1))
        echo "$current_user/$user_count: $username" >> "$progress_file"

        local domains
        domains=$(enumerate_user_domains "$username")
        if [ -n "$domains" ]; then
            domain_list="${domain_list}${domains}"$'\n'
        fi
    done <<< "$users"

    # Deduplicate and sort
    echo "$domain_list" | sort -u | grep -v "^$" | tee "$cache_file"

    rm -f "$progress_file"
}

# ============================================================================
# FILTERING FUNCTIONS
# ============================================================================

# Filter accounts by name pattern
filter_accounts_by_name() {
    local pattern="$1"
    [ -z "$pattern" ] && return 1

    local all_accounts
    all_accounts=$(enumerate_all_accounts)

    echo "$all_accounts" | grep -i "$pattern" || true
}

# Filter accounts by resource usage threshold
filter_accounts_by_threshold() {
    local threshold_mb="${1:-1000}"
    local direction="${2:-above}"  # above or below

    local all_accounts
    all_accounts=$(enumerate_all_accounts)

    local filtered=""
    while IFS= read -r username; do
        [ -z "$username" ] && continue

        local usage_mb
        usage_mb=$(get_account_disk_usage "$username")

        if [ "$direction" = "above" ] && [ "$usage_mb" -gt "$threshold_mb" ]; then
            filtered="${filtered}${username}"$'\n'
        elif [ "$direction" = "below" ] && [ "$usage_mb" -lt "$threshold_mb" ]; then
            filtered="${filtered}${username}"$'\n'
        fi
    done <<< "$all_accounts"

    echo "$filtered" | grep -v "^$"
}

# Filter domains by name pattern
filter_domains_by_name() {
    local pattern="$1"
    [ -z "$pattern" ] && return 1

    local all_domains
    all_domains=$(enumerate_all_domains)

    echo "$all_domains" | grep -i "$pattern" || true
}

# Filter domains by traffic level
filter_domains_by_traffic() {
    local min_requests="${1:-100}"  # Minimum requests per second
    local direction="${2:-above}"   # above or below

    local all_domains
    all_domains=$(enumerate_all_domains)

    local filtered=""
    while IFS= read -r domain; do
        [ -z "$domain" ] && continue

        local peak_concurrent
        peak_concurrent=$(get_domain_peak_concurrent "$domain")

        if [ "$direction" = "above" ] && [ "$peak_concurrent" -gt "$min_requests" ]; then
            filtered="${filtered}${domain}"$'\n'
        elif [ "$direction" = "below" ] && [ "$peak_concurrent" -lt "$min_requests" ]; then
            filtered="${filtered}${domain}"$'\n'
        fi
    done <<< "$all_domains"

    echo "$filtered" | grep -v "^$"
}

# Filter domains by optimization status
filter_domains_by_optimization_status() {
    local status="${1:-needs_optimization}"  # needs_optimization or already_optimized

    local all_domains
    all_domains=$(enumerate_all_domains)

    local filtered=""
    while IFS= read -r domain; do
        [ -z "$domain" ] && continue

        local is_optimized
        is_optimized=$(is_domain_optimized "$domain")

        if [ "$status" = "needs_optimization" ] && [ "$is_optimized" = "0" ]; then
            filtered="${filtered}${domain}"$'\n'
        elif [ "$status" = "already_optimized" ] && [ "$is_optimized" = "1" ]; then
            filtered="${filtered}${domain}"$'\n'
        fi
    done <<< "$all_domains"

    echo "$filtered" | grep -v "^$"
}

# ============================================================================
# DOMAIN INFORMATION FUNCTIONS
# ============================================================================

# Get comprehensive PHP-FPM information for a domain
get_domain_php_info() {
    local domain="$1"
    [ -z "$domain" ] && return 1

    local owner username pool_name pool_path

    # Find domain owner
    owner=$(find_domain_owner "$domain")
    [ -z "$owner" ] && return 1

    # Find PHP pool
    pool_name=$(php_detector_get_pool_name "$domain")
    pool_path=$(php_detector_get_pool_config "$domain")

    # Return info in structured format
    cat << EOF
domain=$domain
owner=$owner
pool_name=$pool_name
pool_path=$pool_path
EOF
}

# Get disk usage for an account
get_account_disk_usage() {
    local username="$1"
    [ -z "$username" ] && return 1

    case "${SYS_CONTROL_PANEL:-unknown}" in
        cpanel)
            _get_cpanel_account_usage "$username"
            ;;
        plesk)
            _get_plesk_account_usage "$username"
            ;;
        interworx)
            _get_interworx_account_usage "$username"
            ;;
        *)
            _get_system_account_usage "$username"
            ;;
    esac
}

_get_cpanel_account_usage() {
    local username="$1"
    local home="/home/$username"
    if [ -d "$home" ]; then
        du -sb "$home" 2>/dev/null | awk '{printf "%.0f", $1/1048576}'
    fi
}

_get_plesk_account_usage() {
    local username="$1"
    local vhost_path="/var/www/vhosts/$username"
    if [ -d "$vhost_path" ]; then
        du -sb "$vhost_path" 2>/dev/null | awk '{printf "%.0f", $1/1048576}'
    fi
}

_get_interworx_account_usage() {
    local username="$1"
    local home="/home/$username"
    if [ -d "$home" ]; then
        du -sb "$home" 2>/dev/null | awk '{printf "%.0f", $1/1048576}'
    fi
}

_get_system_account_usage() {
    local username="$1"
    local home
    home=$(getent passwd "$username" | cut -d: -f6)
    if [ -n "$home" ] && [ -d "$home" ]; then
        du -sb "$home" 2>/dev/null | awk '{printf "%.0f", $1/1048576}'
    fi
}

# Get peak concurrent requests for a domain
get_domain_peak_concurrent() {
    local domain="$1"
    [ -z "$domain" ] && return 1

    local log_file
    log_file=$(find_domain_access_log "$domain")

    if [ -z "$log_file" ] || [ ! -f "$log_file" ]; then
        echo "0"
        return 1
    fi

    # Analyze access log for peak concurrent requests
    # Apache logs: timestamp is [DD/Mon/YYYY:HH:MM:SS]
    # Extract HH:MM (hour and minute) for minute-level granularity
    # Count requests per minute, estimate concurrent = requests/min * avg_duration / 60
    # Assumption: average PHP request takes ~1-2 seconds (multiplier 0.15)
    tail -100000 "$log_file" 2>/dev/null | \
        awk '{print $4}' | \
        sed 's/\[//; s/\].*//' | \
        awk -F: '{print $2 ":" $3}' | \
        sort | uniq -c | \
        sort -rn | head -1 | \
        awk '{requests=$1; concurrent = int(requests * 0.15); if (concurrent < 1) concurrent = (requests > 0 ? 1 : 0); print concurrent}' || echo "0"
}

# Check if a domain is already optimized
is_domain_optimized() {
    local domain="$1"
    [ -z "$domain" ] && return 1

    # Check if pool has been recently optimized (within last 7 days)
    local pool_path
    pool_path=$(php_detector_get_pool_config "$domain")

    if [ -z "$pool_path" ] || [ ! -f "$pool_path" ]; then
        echo "0"
        return 0
    fi

    # Check if pm.max_children is set to something other than default (40)
    local current_max
    current_max=$(grep -oP 'pm\.max_children\s*=\s*\K\d+' "$pool_path" 2>/dev/null || echo "40")

    if [ "$current_max" != "40" ]; then
        echo "1"
    else
        echo "0"
    fi
}

# Find which user owns a domain
find_domain_owner() {
    local domain="$1"
    [ -z "$domain" ] && return 1

    case "${SYS_CONTROL_PANEL:-unknown}" in
        cpanel)
            grep "^${domain}:" /etc/trueuserdomains 2>/dev/null | cut -d: -f2 | tr -d ' '
            ;;
        plesk)
            if command_exists mysql && [ -f /etc/psa/.psa.shadow ]; then
                mysql -Ns psa -e "SELECT u.login FROM domains d JOIN sys_users u ON d.id=u.domain_id WHERE d.name='$domain' LIMIT 1" 2>/dev/null
            fi
            ;;
        interworx)
            grep -l "^${domain}$" /etc/httpd/conf.d/vhost_*.conf 2>/dev/null | \
                xargs grep "SuexecUserGroup" 2>/dev/null | \
                head -1 | awk '{print $2}'
            ;;
        *)
            echo ""
            ;;
    esac
}

# Find access log for a domain
find_domain_access_log() {
    local domain="$1"
    [ -z "$domain" ] && return 1

    case "${SYS_CONTROL_PANEL:-unknown}" in
        cpanel)
            # cPanel standard locations for access logs
            # CRITICAL: Must check HTTPS (ssl_log) first since that's where 95%+ of traffic is
            # Format: /var/log/apache2/domlogs/DOMAIN-ssl_log (HTTPS) or DOMAIN (HTTP)
            local log_file

            # Try standard cPanel domlogs directory FIRST - PREFER SSL LOG (HTTPS)
            # Most modern traffic is HTTPS, so -ssl_log has the real traffic data
            if [ -f "/var/log/apache2/domlogs/${domain}-ssl_log" ]; then
                log_file="/var/log/apache2/domlogs/${domain}-ssl_log"
            elif [ -f "/var/log/apache2/domlogs/${domain}" ]; then
                log_file="/var/log/apache2/domlogs/${domain}"
            fi

            # If not found, try user's access-logs directory (symlink, follows)
            if [ -z "$log_file" ]; then
                local owner
                owner=$(find_domain_owner "$domain")
                if [ -n "$owner" ] && [ -d "/home/${owner}/access-logs" ]; then
                    if [ -f "/home/${owner}/access-logs/${domain}-ssl_log" ]; then
                        log_file="/home/${owner}/access-logs/${domain}-ssl_log"
                    elif [ -f "/home/${owner}/access-logs/${domain}" ]; then
                        log_file="/home/${owner}/access-logs/${domain}"
                    fi
                fi
            fi

            # Try alternative cPanel path
            if [ -z "$log_file" ] && [ -d "/etc/apache2/logs/domlogs" ]; then
                if [ -f "/etc/apache2/logs/domlogs/${domain}-ssl_log" ]; then
                    log_file="/etc/apache2/logs/domlogs/${domain}-ssl_log"
                elif [ -f "/etc/apache2/logs/domlogs/${domain}" ]; then
                    log_file="/etc/apache2/logs/domlogs/${domain}"
                fi
            fi

            echo "$log_file"
            ;;
        plesk)
            # Plesk standard locations
            # Format varies: /var/www/vhosts/DOMAIN/logs/ or /var/www/vhosts/system/DOMAIN/logs/
            find "/var/www/vhosts" -path "*/logs/*" -name "*access*" -o -path "*/system/${domain}/logs/*" 2>/dev/null | head -1
            ;;
        interworx)
            # InterWorx standard location: /home/USER/var/DOMAIN/logs/
            find "/home/*/var/${domain}/logs" -type f -name "*access*" 2>/dev/null | head -1
            ;;
        *)
            # Standalone/unknown - search common locations
            local log_file
            log_file=$(find "/var/log/apache2/domlogs" -maxdepth 1 -type f -name "*${domain}*" 2>/dev/null | head -1)
            if [ -z "$log_file" ]; then
                log_file=$(find "/var/log" -maxdepth 2 -type f -name "*${domain}*access*" 2>/dev/null | head -1)
            fi
            echo "$log_file"
            ;;
    esac
}

# ============================================================================
# HELPER FUNCTIONS
# ============================================================================

# Get count of total accounts
get_total_account_count() {
    enumerate_all_accounts | wc -l
}

# Get count of total domains
get_total_domain_count() {
    enumerate_all_domains | wc -l
}

# Clear enumeration cache
clear_enumeration_cache() {
    rm -f /tmp/php-scanner-*-cache-* 2>/dev/null || true
}

# Display enumeration progress (for use in larger operations)
show_enumeration_progress() {
    local current="$1"
    local total="$2"

    if [ -z "$total" ] || [ "$total" -eq 0 ]; then
        return 0
    fi

    local percent=$((current * 100 / total))
    local filled=$((percent / 5))
    local empty=$((20 - filled))

    printf "Progress: [%-20s] %3d%% (%d/%d)\r" \
        "$(printf '#%.0s' $(seq 1 $filled))$(printf ' %.0s' $(seq 1 $empty))" \
        "$percent" "$current" "$total"
}

export -f enumerate_all_accounts
export -f enumerate_user_domains
export -f enumerate_all_domains
export -f filter_accounts_by_name
export -f filter_accounts_by_threshold
export -f filter_domains_by_name
export -f filter_domains_by_traffic
export -f filter_domains_by_optimization_status
export -f get_domain_php_info
export -f get_account_disk_usage
export -f get_domain_peak_concurrent
export -f is_domain_optimized
export -f find_domain_owner
export -f find_domain_access_log
export -f get_total_account_count
export -f get_total_domain_count
export -f clear_enumeration_cache
export -f show_enumeration_progress
