#!/bin/bash

################################################################################
# Fast 500 Error Tracker
################################################################################
# Purpose: ONLY track 500 errors - find them fast and show WHY
# No menus, no options - just find 500s and diagnose the root cause
################################################################################

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
source "$SCRIPT_DIR/lib/common-functions.sh"
source "$SCRIPT_DIR/lib/system-detect.sh"
source "$SCRIPT_DIR/lib/user-manager.sh"
source "$SCRIPT_DIR/lib/ip-reputation.sh"

# Ensure color variables are set
DIM='\033[2m'
BOLD='\033[1m'

print_banner "Fast 500 Error Tracker"

echo ""
echo "Scanning for 500 errors and diagnosing root causes..."
echo ""

# Ask for time range
echo -e "${CYAN}How far back to scan?${NC}"
echo -e "  ${CYAN}1)${NC} Last 24 hours (default)"
echo -e "  ${CYAN}2)${NC} Last 7 days"
echo -e "  ${CYAN}3)${NC} Last 30 days"
echo -e "  ${CYAN}0)${NC} Cancel and return to menu"
echo ""

# Validate time_choice input
while true; do
    read -p "Select option [1]: " time_choice
    time_choice=${time_choice:-1}

    if ! [[ "$time_choice" =~ ^[0-3]$ ]]; then
        print_error "Invalid choice. Please enter 0, 1, 2, or 3"
        continue
    fi

    case $time_choice in
        0)
            echo ""
            echo "Scan cancelled."
            echo ""
            exit 0
            ;;
        1) HOURS_TO_SCAN=24; break ;;
        2) HOURS_TO_SCAN=168; break ;;
        3) HOURS_TO_SCAN=720; break ;;
    esac
done

echo ""
echo "→ Scanning last $HOURS_TO_SCAN hours of access logs..."
echo ""

# Temporary files
TEMP_DIR="/tmp/500-tracker-$$"
mkdir -p "$TEMP_DIR"
trap '[ -n "$TEMP_DIR" ] && rm -rf "$TEMP_DIR"' EXIT

ERRORS_500="$TEMP_DIR/errors_500.txt"
ERROR_DETAILS="$TEMP_DIR/error_details.txt"

# Configuration - Use system-detected paths
DOMLOGS_DIR="${SYS_LOG_DIR}"
CONTROL_PANEL="${SYS_CONTROL_PANEL}"

# Get cutoff time
cutoff_time=$(date -d "$HOURS_TO_SCAN hours ago" +%s 2>/dev/null || echo "0")

declare -A domain_count
declare -A domain_user
total_500s=0
filtered_bots=0

# Scan all domain access logs for 500 errors (including subdirectories)
while IFS= read -r log; do
    [ -f "$log" ] || continue
    [[ "$log" =~ (bytes_log|offset|error_log|ftpxferlog|-ssl_log)$ ]] && continue

    # Extract domain from log filename
    domain="${log##*/}"
    domain="${domain%%-*}"

    # Skip non-domain system logs (proxy, localhost, etc.)
    [[ "$domain" =~ ^(proxy|localhost|default|cpanel|webmail|whm|cpcalendars|cpcontacts|webdisk)$ ]] && continue

    # Find user for this domain - Multi-panel support
    user=""
    case "$CONTROL_PANEL" in
        cpanel)
            user=$(grep "^${domain}:" /etc/userdatadomains 2>/dev/null | cut -d: -f2 | awk -F'==' '{print $1}' | head -1)
            ;;
        interworx)
            user=$(grep -l "ServerName ${domain}" /etc/httpd/conf.d/vhost_*.conf 2>/dev/null | head -1 | \
                   xargs grep "SuexecUserGroup" 2>/dev/null | awk '{print $2}')
            ;;
        plesk)
            user=$(plesk bin subscription --info "$domain" 2>/dev/null | grep "Owner" | awk '{print $2}')
            ;;
    esac
    [ -z "$user" ] && user="unknown"

    domain_user["$domain"]="$user"
    
    # Scan for 500 errors in this log
    while IFS= read -r line; do
        # Check for 500 status code
        if [[ "$line" =~ '"'[[:space:]](5[0-9]{2})[[:space:]] ]]; then
            status="${BASH_REMATCH[1]}"

            # Time filtering
            if [ "$cutoff_time" != "0" ]; then
                if [[ "$line" =~ \[([0-9]{2}/[A-Z][a-z]{2}/[0-9]{4}:[0-9]{2}:[0-9]{2}:[0-9]{2}) ]]; then
                    log_date="${BASH_REMATCH[1]}"
                    log_time=$(date -d "${log_date/:/ }" +%s 2>/dev/null || echo "0")
                    [ "$log_time" != "0" ] && [ "$log_time" -lt "$cutoff_time" ] && continue
                fi
            fi

            # Parse log line to get IP first
            read -r ip _ _ timestamp _ request _ _ <<< "$line"

            # IP-based filtering - skip non-relevant IPs
            # Skip localhost/internal IPs
            if [[ "$ip" =~ ^(127\.|::1|10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.) ]]; then
                ((filtered_bots++))
                continue
            fi

            # Skip common cloud scanner IPs and known bot networks
            # AWS, GCP, Azure scanner ranges, security scanners
            if [[ "$ip" =~ ^(3\.|13\.|18\.|34\.|35\.|52\.|54\.) ]] || \
               [[ "$ip" =~ ^(104\.196\.|104\.154\.|130\.211\.|35\.184\.|35\.185\.|35\.186\.|35\.187\.|35\.188\.|35\.189\.|35\.19) ]] || \
               [[ "$ip" =~ ^(20\.|40\.|51\.|52\.|13\.64\.|13\.65\.|13\.66\.|13\.67\.|13\.68\.) ]]; then
                # Check if it's actually a bot by examining user agent
                line_lower="${line,,}"
                if [[ "$line_lower" =~ (bot|crawler|spider|scanner|monitor|cloud|amazon|google|microsoft|azure) ]]; then
                    ((filtered_bots++))
                    # Track bot IP with BOT flag
                    flag_ip_attack "$ip" "BOT" 0 "500 error - filtered as bot/scanner" >/dev/null 2>&1 &
                    continue
                fi
            fi

            # Bot/Scanner filtering - skip noise
            line_lower="${line,,}"
            if [[ "$line_lower" =~ (bot|crawler|spider|scraper|scanner|check|monitor|uptime|pingdom|newrelic|datadog|nagios|zabbix|prtg|gomez|keynote|catchpoint|dotcom-monitor|site24x7|uptimerobot|statuscake|nodequery|hetrixtools|freshping|uptrendscom|siteuptime|montastic|updown\.io|apex|alertsite|webmon|wormly) ]]; then
                ((filtered_bots++))
                # Track monitoring/uptime bot
                flag_ip_attack "$ip" "BOT" 0 "Monitoring/uptime bot" >/dev/null 2>&1 &
                continue
            fi
            if [[ "$line_lower" =~ (semrush|ahrefs|moz|majestic|serpstat|screaming|screamingfrog|sitebulb|linkchecker|validator|scanner|security|acunetix|nessus|openvas|burp|nikto|skipfish|w3af|sqlmap|metasploit|nmap|masscan|zmap|shodan|censys|binaryedge) ]]; then
                ((filtered_bots++))
                # Track scanner with higher score
                flag_ip_attack "$ip" "SCANNER" 0 "Security scanner detected" >/dev/null 2>&1 &
                continue
            fi
            if [[ "$line_lower" =~ (curl|wget|python|perl|ruby|java|go-http|libwww|axios|node-fetch|http\.client|httpie|postman|insomnia|apachehttp|okhttp|httpclient) ]]; then
                ((filtered_bots++))
                # Track programmatic access
                flag_ip_attack "$ip" "BOT" 0 "HTTP library/tool" >/dev/null 2>&1 &
                continue
            fi
            
            # Extract URL
            if [[ "$request" =~ '"'[A-Z]+[[:space:]]([^[:space:]]+) ]]; then
                url="${BASH_REMATCH[1]:0:80}"
            else
                url="/"
            fi
            
            # Extract timestamp
            if [[ "$line" =~ \[([^]]+)\] ]]; then
                timestamp="${BASH_REMATCH[1]}"
            else
                timestamp="unknown"
            fi
            
            ((domain_count["$domain"]++))
            ((total_500s++))

            # Track IP in reputation database (500 error = slight increase in score)
            # Most 500s are due to server issues, not attacks, so low score increase
            increment_ip_hits "$ip" 1 >/dev/null 2>&1 &

            # Save for analysis
            echo "$domain|$user|$status|$url|$timestamp|$ip" >> "$ERRORS_500"
        fi
    done < <(tail -n 100000 "$log" 2>/dev/null)
done < <(
    # Multi-panel log discovery
    case "$CONTROL_PANEL" in
        cpanel)
            # cPanel: Centralized domlogs
            find "$DOMLOGS_DIR" -type f ! -name "*bytes_log" ! -name "*offset*" ! -name "*error_log" ! -name "*ftpxferlog*" ! -name "*-ssl_log" 2>/dev/null
            ;;
        interworx)
            # InterWorx: Per-domain logs in user homes (uses 'transfer.log')
            find /home/*/var/*/logs -type f -name "transfer.log" 2>/dev/null
            ;;
        plesk)
            # Plesk: System vhosts logs
            find /var/www/vhosts/system/*/logs -type f \( -name "access_log" -o -name "access_ssl_log" \) 2>/dev/null
            ;;
        *)
            # Standalone: Try common locations
            if [ -f "/var/log/httpd/access_log" ]; then echo "/var/log/httpd/access_log"; fi
            if [ -f "/var/log/apache2/access.log" ]; then echo "/var/log/apache2/access.log"; fi
            ;;
    esac
)

if [ "$total_500s" -eq 0 ]; then
    echo ""
    echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
    echo -e "${GREEN} ✓ NO 500 ERRORS FOUND IN LAST $HOURS_TO_SCAN HOURS!${NC}"
    echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
    echo ""
    exit 0
fi

echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo " 500 ERRORS DETECTED: $total_500s errors (filtered out $filtered_bots bot/scanner requests)"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""

echo -e "${RED}${BOLD}TOP AFFECTED DOMAINS:${NC}"
echo ""

# Sort and display top domains
for domain in "${!domain_count[@]}"; do
    echo "${domain_count[$domain]} $domain ${domain_user[$domain]}"
done | sort -rn | head -10 | while read count domain user; do
    printf "  ${RED}●${NC} %-40s ${BOLD}%4d errors${NC}  (user: %s)\n" "$domain" "$count" "$user"
done

echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo " DIAGNOSING ROOT CAUSES"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""

# Detailed diagnostic tracking - per URL/file
DETAILED_DIAGNOSIS="$TEMP_DIR/detailed_diagnosis.txt"
> "$DETAILED_DIAGNOSIS"

declare -A diagnosed_causes
declare -A cause_examples

total_to_diagnose=$(wc -l < "$ERRORS_500")
current_line=0

echo "Analyzing $total_to_diagnose errors for root causes..."
echo ""

while IFS='|' read -r domain user status url timestamp ip; do
    [ -z "$domain" ] && continue

    ((current_line++))
    # Show progress every 500 errors
    if [ $((current_line % 500)) -eq 0 ]; then
        echo -ne "\rAnalyzed $current_line / $total_to_diagnose errors..."
    fi

    diagnosis=""
    cause="UNKNOWN"
    specific_file=""

    # Get document root
    docroot="/home/$user/public_html"

    # Try to determine the actual file being requested
    if [[ "$url" =~ ^/([^?]+) ]]; then
        url_path="${BASH_REMATCH[1]}"

        # Handle common patterns
        if [ -z "$url_path" ] || [ "$url_path" = "/" ]; then
            possible_files=("$docroot/index.php" "$docroot/index.html")
        elif [[ "$url_path" =~ \.php$ ]]; then
            possible_files=("$docroot/$url_path")
        else
            possible_files=("$docroot/$url_path" "$docroot/${url_path}.php" "$docroot/$url_path/index.php")
        fi

        # Find the actual file
        for pf in "${possible_files[@]}"; do
            if [ -f "$pf" ]; then
                specific_file="$pf"
                break
            fi
        done
    fi

    # Find PHP error log - check multiple locations
    error_log=""
    if [ "$user" != "unknown" ]; then
        for potential_log in \
            "/home/$user/public_html/error_log" \
            "/home/$user/logs/error_log" \
            "/home/$user/error_log" \
            "/var/log/apache2/domlogs/$domain-error_log" \
            "/usr/local/apache/domlogs/$domain"; do

            if [ -f "$potential_log" ]; then
                error_log="$potential_log"
                break
            fi
        done
    fi

    # Check if error log exists and has recent errors
    if [ -n "$error_log" ] && [ -f "$error_log" ]; then
        # Look for errors matching this URL/timestamp
        recent_error=$(tail -1000 "$error_log" | grep "$url" | tail -1)

        # If no URL match, get most recent error
        [ -z "$recent_error" ] && recent_error=$(tail -500 "$error_log" | grep -E "Fatal error|Parse error|syntax error|memory.*exhausted|database|MySQL|Permission denied|failed to open stream" | tail -1)

        if [ -n "$recent_error" ]; then
            # Extract file path from error if present
            if [[ "$recent_error" =~ in[[:space:]](/[^:]+\.php) ]]; then
                error_file="${BASH_REMATCH[1]}"
                specific_file="$error_file"
            fi

            # Determine cause and diagnose
            if [[ "$recent_error" =~ (memory.*exhausted|Allowed memory size) ]]; then
                cause="PHP_MEMORY_EXHAUSTED"

                # Check current memory limit
                mem_limit=$(grep -h "memory_limit" "$docroot/.user.ini" "$docroot/../.php.ini" 2>/dev/null | tail -1 | cut -d'=' -f2 | tr -d ' ')
                [ -z "$mem_limit" ] && mem_limit=$(php -r "echo ini_get('memory_limit');" 2>/dev/null)

                diagnosis="$domain$url - Memory exhausted (current limit: ${mem_limit:-unknown})"
                [ -n "$specific_file" ] && diagnosis="$diagnosis - File: $specific_file"

            elif [[ "$recent_error" =~ (failed to open stream|Permission denied) ]]; then
                cause="PERMISSION_ERROR"

                # Extract the file with permission issue
                if [[ "$recent_error" =~ failed\ to\ open\ stream.*\'([^\']+)\' ]]; then
                    perm_file="${BASH_REMATCH[1]}"
                elif [[ "$recent_error" =~ Permission\ denied.*\'([^\']+)\' ]]; then
                    perm_file="${BASH_REMATCH[1]}"
                else
                    perm_file="$specific_file"
                fi

                # Check permissions on that specific file
                if [ -n "$perm_file" ] && [ -e "$perm_file" ]; then
                    file_perms=$(stat -c "%a" "$perm_file" 2>/dev/null)
                    file_owner=$(stat -c "%U:%G" "$perm_file" 2>/dev/null)
                    diagnosis="$domain$url - Permission denied on: $perm_file (perms: $file_perms, owner: $file_owner)"

                    # Check if file is readable by Apache
                    if [ -f "$perm_file" ]; then
                        if ! sudo -u nobody test -r "$perm_file" 2>/dev/null; then
                            diagnosis="$diagnosis - File NOT readable by Apache (nobody user)"
                        fi
                    fi
                else
                    diagnosis="$domain$url - Permission denied (file in error: $perm_file - does not exist)"
                fi

            elif [[ "$recent_error" =~ (Fatal error|PHP Fatal error) ]]; then
                if [[ "$recent_error" =~ (undefined function|Call to undefined function) ]]; then
                    cause="MISSING_PHP_FUNCTION"

                    # Extract function name
                    if [[ "$recent_error" =~ Call\ to\ undefined\ function\ ([a-zA-Z0-9_]+) ]]; then
                        missing_func="${BASH_REMATCH[1]}"

                        # Check which extension provides this function
                        ext_info=$(php -r "if(function_exists('$missing_func')) echo 'EXISTS'; else echo 'MISSING';" 2>&1)

                        diagnosis="$domain$url - Missing function: $missing_func"
                        [ -n "$specific_file" ] && diagnosis="$diagnosis - in file: $specific_file"
                    else
                        diagnosis="$domain$url - Missing PHP function - $recent_error"
                    fi
                else
                    cause="PHP_FATAL_ERROR"
                    diagnosis="$domain$url - PHP Fatal Error"
                    [ -n "$specific_file" ] && diagnosis="$diagnosis - File: $specific_file"
                    diagnosis="$diagnosis - ${recent_error:0:200}"
                fi

            elif [[ "$recent_error" =~ (Parse error|syntax error) ]]; then
                cause="PHP_SYNTAX_ERROR"

                # Extract line number if present
                if [[ "$recent_error" =~ line\ ([0-9]+) ]]; then
                    error_line="${BASH_REMATCH[1]}"
                    diagnosis="$domain$url - PHP Syntax Error at line $error_line"
                else
                    diagnosis="$domain$url - PHP Syntax Error"
                fi
                [ -n "$specific_file" ] && diagnosis="$diagnosis - File: $specific_file"

            elif [[ "$recent_error" =~ (database|MySQL|Can\'t connect|Access denied for user) ]]; then
                cause="DATABASE_CONNECTION"

                if [[ "$recent_error" =~ Access\ denied\ for\ user\ \'([^\']+)\' ]]; then
                    db_user="${BASH_REMATCH[1]}"
                    diagnosis="$domain$url - Database access denied for user: $db_user"
                elif [[ "$recent_error" =~ Unknown\ database\ \'([^\']+)\' ]]; then
                    db_name="${BASH_REMATCH[1]}"
                    diagnosis="$domain$url - Unknown database: $db_name"
                else
                    diagnosis="$domain$url - Database connection error"
                fi
                [ -n "$specific_file" ] && diagnosis="$diagnosis - from file: $specific_file"
            fi

            # Save detailed diagnosis only if we identified a specific cause
            if [ "$cause" != "UNKNOWN" ] && [ -n "$diagnosis" ]; then
                echo "$cause|$diagnosis" >> "$DETAILED_DIAGNOSIS"
                ((diagnosed_causes["$cause"]++))
                [ -z "${cause_examples[$cause]}" ] && cause_examples["$cause"]="$diagnosis"
            else
                # No matching error in error_log - run comprehensive checks
                if [ "$user" != "unknown" ]; then
                    issue_found=""

                    # Check 1: .htaccess issues
                    if [ -f "$docroot/.htaccess" ]; then
                        htaccess_file="$docroot/.htaccess"
                        htaccess_issues=""

                        # Invalid PHP directives
                        if grep -qE "^[[:space:]]*(php_value|php_flag|php_admin_value|php_admin_flag)" "$htaccess_file" 2>/dev/null; then
                            if ! apache2ctl -M 2>/dev/null | grep -q "php.*module"; then
                                htaccess_issues="PHP directives incompatible with FPM"
                            fi
                        fi

                        # Malformed RewriteRule
                        bad_rewrite=$(grep -nE "RewriteRule.*\[.*[^]]*$" "$htaccess_file" 2>/dev/null | head -1)
                        [ -n "$bad_rewrite" ] && htaccess_issues="${htaccess_issues:+$htaccess_issues; }Malformed RewriteRule: ${bad_rewrite:0:50}"

                        # Missing RewriteBase with RewriteRule
                        if grep -q "RewriteRule" "$htaccess_file" 2>/dev/null; then
                            if ! grep -q "RewriteBase" "$htaccess_file" 2>/dev/null; then
                                # Check if rules use relative paths
                                if grep -qE "RewriteRule.*\^[^/]" "$htaccess_file" 2>/dev/null; then
                                    htaccess_issues="${htaccess_issues:+$htaccess_issues; }Missing RewriteBase with relative paths"
                                fi
                            fi
                        fi

                        if [ -n "$htaccess_issues" ]; then
                            cause="HTACCESS_ERROR"
                            diagnosis="$domain$url - $htaccess_issues"
                            issue_found="yes"
                        fi
                    fi

                    # Check 2: PHP file exists and is readable
                    if [ -z "$issue_found" ] && [ -n "$specific_file" ]; then
                        if [ ! -f "$specific_file" ]; then
                            cause="FILE_NOT_FOUND"
                            diagnosis="$domain$url - File does not exist: $specific_file"
                            issue_found="yes"
                        elif [ ! -r "$specific_file" ]; then
                            file_perms=$(stat -c "%a" "$specific_file" 2>/dev/null)
                            cause="PERMISSION_ERROR"
                            diagnosis="$domain$url - File not readable: $specific_file (perms: $file_perms)"
                            issue_found="yes"
                        fi
                    fi

                    # Check 3: Document root permissions
                    if [ -z "$issue_found" ]; then
                        if [ ! -d "$docroot" ]; then
                            cause="DOCROOT_MISSING"
                            diagnosis="$domain$url - Document root does not exist: $docroot"
                            issue_found="yes"
                        else
                            docroot_perms=$(stat -c "%a" "$docroot" 2>/dev/null)
                            if [ "$docroot_perms" != "755" ] && [ "$docroot_perms" != "750" ] && [ "$docroot_perms" != "711" ]; then
                                cause="PERMISSION_ERROR"
                                diagnosis="$domain$url - Docroot bad perms: $docroot ($docroot_perms, should be 755)"
                                issue_found="yes"
                            fi
                        fi
                    fi

                    # Check 4: PHP handler/version issues
                    if [ -z "$issue_found" ] && [ -n "$specific_file" ] && [ -f "$specific_file" ]; then
                        # Check if PHP is configured for this domain
                        php_handler=$(grep -i "phpversion\|php_admin_value" /var/cpanel/userdata/$user/$domain 2>/dev/null | head -1)
                        if [ -z "$php_handler" ]; then
                            # Check if .htaccess tries to set PHP version but fails
                            if grep -qE "AddHandler.*php|SetHandler.*php" "$docroot/.htaccess" 2>/dev/null; then
                                cause="PHP_HANDLER_ERROR"
                                diagnosis="$domain$url - PHP handler misconfigured (check .htaccess AddHandler/SetHandler)"
                                issue_found="yes"
                            fi
                        fi
                    fi

                    # Check 5: WordPress-specific issues (if WP detected)
                    if [ -z "$issue_found" ] && [ -f "$docroot/wp-config.php" ]; then
                        # Check if wp-config.php is readable
                        if [ ! -r "$docroot/wp-config.php" ]; then
                            cause="PERMISSION_ERROR"
                            diagnosis="$domain$url - wp-config.php not readable"
                            issue_found="yes"
                        else
                            # Check for WP_DEBUG causing issues
                            if grep -q "define.*WP_DEBUG.*true" "$docroot/wp-config.php" 2>/dev/null; then
                                # Check if WP_DEBUG_DISPLAY is also true (can cause 500s with some errors)
                                if grep -q "define.*WP_DEBUG_DISPLAY.*true" "$docroot/wp-config.php" 2>/dev/null; then
                                    cause="WP_DEBUG_ERROR"
                                    diagnosis="$domain$url - WP_DEBUG_DISPLAY enabled (may cause 500 on warnings)"
                                    issue_found="yes"
                                fi
                            fi
                        fi
                    fi

                    # Save diagnosis if we found an issue
                    if [ -n "$issue_found" ] && [ -n "$diagnosis" ]; then
                        echo "$cause|$diagnosis" >> "$DETAILED_DIAGNOSIS"
                        ((diagnosed_causes["$cause"]++))
                        [ -z "${cause_examples[$cause]}" ] && cause_examples["$cause"]="$diagnosis"
                    else
                        ((diagnosed_causes["NO_PHP_ERROR_LOGGED"]++))
                    fi
                else
                    ((diagnosed_causes["NO_PHP_ERROR_LOGGED"]++))
                fi
            fi
        else
            # No error in error_log at all - check .htaccess
            if [ "$user" != "unknown" ] && [ -f "$docroot/.htaccess" ]; then
                htaccess_file="$docroot/.htaccess"
                htaccess_issues=""

                # Check for invalid PHP directives
                if grep -qE "^[[:space:]]*(php_value|php_flag|php_admin_value|php_admin_flag)" "$htaccess_file" 2>/dev/null; then
                    if ! apache2ctl -M 2>/dev/null | grep -q "php.*module"; then
                        htaccess_issues="PHP directives (php_value/php_flag) incompatible with current PHP handler (not mod_php)"
                    fi
                fi

                # Check for malformed RewriteRule
                bad_rewrite=$(grep -nE "RewriteRule.*\[.*[^]]*$" "$htaccess_file" 2>/dev/null | head -1)
                if [ -n "$bad_rewrite" ]; then
                    htaccess_issues="${htaccess_issues:+$htaccess_issues; }Malformed RewriteRule: $bad_rewrite"
                fi

                if [ -n "$htaccess_issues" ]; then
                    cause="HTACCESS_ERROR"
                    diagnosis="$domain$url - .htaccess error: $htaccess_issues"
                    echo "$cause|$diagnosis" >> "$DETAILED_DIAGNOSIS"
                    ((diagnosed_causes["$cause"]++))
                    [ -z "${cause_examples[$cause]}" ] && cause_examples["$cause"]="$diagnosis"
                else
                    ((diagnosed_causes["NO_PHP_ERROR_LOGGED"]++))
                fi
            else
                ((diagnosed_causes["NO_PHP_ERROR_LOGGED"]++))
            fi
        fi
    else
        # No error log found - check .htaccess and permissions thoroughly
        if [ "$user" != "unknown" ]; then
            htaccess_file="$docroot/.htaccess"

            if [ -f "$htaccess_file" ]; then
                # Check .htaccess file permissions first
                htaccess_perms=$(stat -c "%a" "$htaccess_file" 2>/dev/null)
                htaccess_owner=$(stat -c "%U:%G" "$htaccess_file" 2>/dev/null)

                # Check if readable by Apache
                htaccess_readable="yes"
                if ! sudo -u nobody test -r "$htaccess_file" 2>/dev/null; then
                    htaccess_readable="no"
                fi

                # Actually validate .htaccess syntax
                htaccess_test=$(apache2ctl -t 2>&1)
                htaccess_issues=""

                # Check for invalid directives
                if grep -qE "^[[:space:]]*(php_value|php_flag|php_admin_value|php_admin_flag)" "$htaccess_file" 2>/dev/null; then
                    if ! apache2ctl -M 2>/dev/null | grep -q "php.*module"; then
                        htaccess_issues="PHP directives (php_value/php_flag) incompatible with current PHP handler (not mod_php)"
                    fi
                fi

                # Check for malformed RewriteRule
                bad_rewrite=$(grep -nE "RewriteRule.*\[.*[^]]*$" "$htaccess_file" 2>/dev/null | head -1)
                if [ -n "$bad_rewrite" ]; then
                    htaccess_issues="${htaccess_issues:+$htaccess_issues; }Malformed RewriteRule: $bad_rewrite"
                fi

                # Check for RewriteCond without following RewriteRule
                orphan_cond=$(grep -n "RewriteCond" "$htaccess_file" | while read line; do
                    linenum=$(echo "$line" | cut -d: -f1)
                    nextline=$((linenum + 1))
                    next=$(sed -n "${nextline}p" "$htaccess_file")
                    if [[ ! "$next" =~ RewriteRule|RewriteCond ]]; then
                        echo "Line $linenum: RewriteCond without RewriteRule"
                    fi
                done | head -1)

                if [ -n "$orphan_cond" ]; then
                    htaccess_issues="${htaccess_issues:+$htaccess_issues; }$orphan_cond"
                fi

                # Check for syntax errors in .htaccess
                if echo "$htaccess_test" | grep -qi "syntax error"; then
                    syntax_err=$(echo "$htaccess_test" | grep -i "syntax error" | head -1)
                    htaccess_issues="${htaccess_issues:+$htaccess_issues; }Apache syntax error: $syntax_err"
                fi

                if [ "$htaccess_readable" = "no" ]; then
                    cause="PERMISSION_ERROR"
                    diagnosis="$domain$url - .htaccess not readable by Apache (perms: $htaccess_perms, owner: $htaccess_owner)"
                    echo "$cause|$diagnosis" >> "$DETAILED_DIAGNOSIS"
                    ((diagnosed_causes["$cause"]++))
                    [ -z "${cause_examples[$cause]}" ] && cause_examples["$cause"]="$diagnosis"
                elif [ -n "$htaccess_issues" ]; then
                    cause="HTACCESS_ERROR"
                    diagnosis="$domain$url - .htaccess error: $htaccess_issues"
                    echo "$cause|$diagnosis" >> "$DETAILED_DIAGNOSIS"
                    ((diagnosed_causes["$cause"]++))
                    [ -z "${cause_examples[$cause]}" ] && cause_examples["$cause"]="$diagnosis"
                else
                    # .htaccess appears valid - check document root and file permissions
                    docroot_perms=$(stat -c "%a" "$docroot" 2>/dev/null)
                    docroot_owner=$(stat -c "%U:%G" "$docroot" 2>/dev/null)

                    if [ "$docroot_perms" != "755" ] && [ "$docroot_perms" != "750" ]; then
                        cause="PERMISSION_ERROR"
                        diagnosis="$domain$url - Document root incorrect permissions (perms: $docroot_perms, owner: $docroot_owner, should be 755)"
                        echo "$cause|$diagnosis" >> "$DETAILED_DIAGNOSIS"
                        ((diagnosed_causes["$cause"]++))
                        [ -z "${cause_examples[$cause]}" ] && cause_examples["$cause"]="$diagnosis"
                    elif [ -n "$specific_file" ] && [ -f "$specific_file" ]; then
                        # Check the specific PHP file permissions
                        file_perms=$(stat -c "%a" "$specific_file" 2>/dev/null)
                        file_owner=$(stat -c "%U:%G" "$specific_file" 2>/dev/null)
                        file_readable="yes"

                        if ! sudo -u nobody test -r "$specific_file" 2>/dev/null; then
                            file_readable="no"
                        fi

                        if [ "$file_readable" = "no" ]; then
                            cause="PERMISSION_ERROR"
                            diagnosis="$domain$url - File not readable by Apache: $specific_file (perms: $file_perms, owner: $file_owner)"
                            echo "$cause|$diagnosis" >> "$DETAILED_DIAGNOSIS"
                            ((diagnosed_causes["$cause"]++))
                            [ -z "${cause_examples[$cause]}" ] && cause_examples["$cause"]="$diagnosis"
                        else
                            ((diagnosed_causes["NO_PHP_ERROR_LOGGED"]++))
                        fi
                    else
                        ((diagnosed_causes["NO_PHP_ERROR_LOGGED"]++))
                    fi
                fi
            else
                # No .htaccess - check document root and file permissions
                docroot_perms=$(stat -c "%a" "$docroot" 2>/dev/null)
                docroot_owner=$(stat -c "%U:%G" "$docroot" 2>/dev/null)

                if [ "$docroot_perms" != "755" ] && [ "$docroot_perms" != "750" ]; then
                    cause="PERMISSION_ERROR"
                    diagnosis="$domain$url - Document root incorrect permissions (perms: $docroot_perms, owner: $docroot_owner, should be 755)"
                    echo "$cause|$diagnosis" >> "$DETAILED_DIAGNOSIS"
                    ((diagnosed_causes["$cause"]++))
                    [ -z "${cause_examples[$cause]}" ] && cause_examples["$cause"]="$diagnosis"
                elif [ -n "$specific_file" ] && [ -f "$specific_file" ]; then
                    # Check the specific PHP file
                    file_perms=$(stat -c "%a" "$specific_file" 2>/dev/null)
                    file_owner=$(stat -c "%U:%G" "$specific_file" 2>/dev/null)

                    if ! sudo -u nobody test -r "$specific_file" 2>/dev/null; then
                        cause="PERMISSION_ERROR"
                        diagnosis="$domain$url - File not readable: $specific_file (perms: $file_perms, owner: $file_owner)"
                        echo "$cause|$diagnosis" >> "$DETAILED_DIAGNOSIS"
                        ((diagnosed_causes["$cause"]++))
                        [ -z "${cause_examples[$cause]}" ] && cause_examples["$cause"]="$diagnosis"
                    else
                        ((diagnosed_causes["NO_ERROR_LOG_FILE"]++))
                    fi
                else
                    ((diagnosed_causes["NO_ERROR_LOG_FILE"]++))
                fi
            fi
        else
            ((diagnosed_causes["NO_ERROR_LOG_FILE"]++))
        fi
    fi
done < "$ERRORS_500"

echo -e "\rAnalyzed $total_to_diagnose / $total_to_diagnose errors - Complete!     "
echo ""

# Display diagnosed causes
echo -e "${CYAN}${BOLD}ROOT CAUSES IDENTIFIED:${NC}"
echo ""

for cause in "${!diagnosed_causes[@]}"; do
    count="${diagnosed_causes[$cause]}"
    echo "$count|$cause"
done | sort -rn | while IFS='|' read count cause; do
    clean_cause=$(echo "$cause" | tr '_' ' ')
    
    case "$cause" in
        PHP_MEMORY_EXHAUSTED)
            echo -e "${RED}$clean_cause${NC} - $count occurrences"
            echo -e "   ${YELLOW}Fix:${NC} Increase memory_limit in /home/USER/public_html/.user.ini"
            echo -e "   ${YELLOW}Set:${NC} memory_limit = 512M"
            ;;
        PHP_FATAL_ERROR)
            echo -e "${RED}$clean_cause${NC} - $count occurrences"
            echo -e "   ${YELLOW}Fix:${NC} Review recent code/plugin changes"
            ;;
        PHP_SYNTAX_ERROR)
            echo -e "${RED}$clean_cause${NC} - $count occurrences"
            echo -e "   ${YELLOW}Fix:${NC} Check for PHP syntax errors in recent file edits"
            ;;
        MISSING_PHP_FUNCTION)
            echo -e "${RED}$clean_cause${NC} - $count occurrences"
            echo -e "   ${YELLOW}Fix:${NC} Install missing PHP extension (check error for which one)"
            ;;
        DATABASE_CONNECTION)
            echo -e "${RED}$clean_cause${NC} - $count occurrences"
            echo -e "   ${YELLOW}Fix:${NC} Check database credentials or MySQL service"
            ;;
        HTACCESS_ERROR)
            echo -e "${RED}.HTACCESS ERROR DETECTED${NC} - $count occurrences"
            ;;
        PERMISSION_ERROR)
            echo -e "${RED}PERMISSION ERROR DETECTED${NC} - $count occurrences"
            ;;
        NO_ERROR_LOG_FILE)
            echo -e "${YELLOW}$clean_cause${NC} - $count occurrences"
            echo -e "   ${YELLOW}Note:${NC} Checked multiple error_log locations - none found"
            echo -e "   ${YELLOW}Check:${NC} May need to enable PHP error logging"
            ;;
        NO_PHP_ERROR_LOGGED)
            echo -e "${YELLOW}$clean_cause${NC} - $count occurrences"
            echo -e "   ${YELLOW}Note:${NC} 500 error but no PHP error in log - likely .htaccess or Apache config"
            ;;
        FILE_NOT_FOUND)
            echo -e "${RED}$clean_cause${NC} - $count occurrences"
            echo -e "   ${YELLOW}Fix:${NC} Requested file does not exist - check URL or restore missing files"
            ;;
        PHP_HANDLER_ERROR)
            echo -e "${RED}PHP HANDLER ERROR${NC} - $count occurrences"
            echo -e "   ${YELLOW}Fix:${NC} PHP handler misconfigured - check cPanel PHP version or .htaccess AddHandler"
            ;;
        WP_DEBUG_ERROR)
            echo -e "${YELLOW}WORDPRESS DEBUG ERROR${NC} - $count occurrences"
            echo -e "   ${YELLOW}Fix:${NC} Disable WP_DEBUG_DISPLAY in wp-config.php or fix underlying warnings"
            ;;
        DOCROOT_MISSING)
            echo -e "${RED}$clean_cause${NC} - $count occurrences"
            echo -e "   ${YELLOW}Fix:${NC} Document root directory missing - restore from backup or check domain configuration"
            ;;
        UNKNOWN)
            # Skip - these are errors we couldn't diagnose
            ;;
        *)
            echo -e "${INFO_COLOR}$clean_cause${NC} - $count occurrences"
            ;;
    esac
    
    # Show example if we have one
    if [ -n "${cause_examples[$cause]}" ]; then
        example="${cause_examples[$cause]}"
        echo -e "   ${DIM}Example: ${example:0:120}...${NC}"
    fi
    echo ""
done

echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo " DETAILED 500 ERROR LIST"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""

# Show most frequent URLs getting 500s
echo "Most Frequent 500 Error URLs:"
echo ""
cut -d'|' -f1,4 "$ERRORS_500" | sort | uniq -c | sort -rn | head -15 | while read count domain_url; do
    domain=$(echo "$domain_url" | cut -d'|' -f1)
    url=$(echo "$domain_url" | cut -d'|' -f2)
    user="${domain_user[$domain]}"
    printf "  ${RED}%4d×${NC} %s%s ${DIM}(user: %s)${NC}\n" "$count" "$domain" "$url" "$user"
done

echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo " SPECIFIC DIAGNOSTICS (per URL/file)"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""

# Show detailed diagnostics grouped by cause and issue pattern
if [ -f "$DETAILED_DIAGNOSIS" ] && [ -s "$DETAILED_DIAGNOSIS" ]; then
    for cause_type in PHP_MEMORY_EXHAUSTED PERMISSION_ERROR HTACCESS_ERROR PHP_FATAL_ERROR PHP_SYNTAX_ERROR MISSING_PHP_FUNCTION DATABASE_CONNECTION FILE_NOT_FOUND PHP_HANDLER_ERROR WP_DEBUG_ERROR DOCROOT_MISSING; do

        cause_count=$(grep "^${cause_type}|" "$DETAILED_DIAGNOSIS" 2>/dev/null | wc -l)
        cause_count=${cause_count//[^0-9]/}  # Remove any non-numeric characters
        cause_count=${cause_count:-0}  # Default to 0 if empty

        if [ "$cause_count" -gt 0 ]; then
            cause_display=$(echo "$cause_type" | tr '_' ' ')
            echo -e "${RED}${BOLD}$cause_display ($cause_count occurrences)${NC}"
            echo ""

            # Group by unique error pattern (not domain)
            declare -A issue_domains

            # First pass: collect all domains per issue pattern
            declare -A pattern_domains_temp

            while IFS='|' read -r ctype full_diag; do
                # Extract just the error part (after domain/)
                issue_pattern=$(echo "$full_diag" | sed 's/^[^ ]* - //')
                domain_part=$(echo "$full_diag" | grep -oP '^[^/]+' 2>/dev/null)

                # Append to temporary storage
                pattern_domains_temp[$issue_pattern]+="$domain_part"$'\n'
            done < <(grep "^${cause_type}|" "$DETAILED_DIAGNOSIS" 2>/dev/null)

            # Second pass: deduplicate and limit to 5 unique domains per pattern
            for pattern in "${!pattern_domains_temp[@]}"; do
                # Get unique domains, limit to 5
                unique_list=$(echo "${pattern_domains_temp[$pattern]}" | sort -u | head -5 | tr '\n' ',')
                # Remove trailing comma
                unique_list=${unique_list%,}

                # Count total unique domains
                total_unique=$(echo "${pattern_domains_temp[$pattern]}" | sort -u | wc -l)

                # Add "..." if there are more than 5
                if [ "$total_unique" -gt 5 ]; then
                    unique_list="$unique_list,..."
                fi

                issue_domains[$pattern]="$unique_list"
            done

            unset pattern_domains_temp

            # Display grouped issues
            shown=0
            for pattern in "${!issue_domains[@]}"; do
                [ "${shown:-0}" -ge 10 ] && break
                ((shown++))

                domains="${issue_domains[$pattern]}"
                domain_count=$(echo "$domains" | tr ',' '\n' | grep -v '^\.\.\.$' | wc -l)

                echo -e "  ${YELLOW}Issue:${NC} $pattern"
                echo -e "  ${DIM}Affected ($domain_count):${NC} ${domains//,/, }"
                echo ""
            done

            if [ "${#issue_domains[@]}" -gt 10 ]; then
                remaining=$((${#issue_domains[@]} - 10))
                echo -e "  ${DIM}... and $remaining more issue patterns${NC}"
                echo ""
            fi

            unset issue_domains
        fi
    done
else
    echo "No detailed diagnostics available."
    echo ""
fi

echo "Full error list saved to: $ERRORS_500"
echo "Detailed diagnostics saved to: $DETAILED_DIAGNOSIS"
echo ""

press_enter
