#!/bin/bash
########################################
# Health Check Monitor (Cron-Friendly)
# Aggregates all health checks and alerts
# Run via cron every 5 minutes
########################################

# Get the directory where this script lives
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
LOG_FILE="$PROJECT_ROOT/storage/logs/health-check-monitor.log"
ALERT_FILE="$PROJECT_ROOT/storage/logs/health-alerts.log"

# Email settings
ALERT_EMAIL="${HEALTH_CHECK_ALERT_EMAIL:-admin@globalgala.com}"

# Load cron context library
source "$SCRIPT_DIR/_cron-context.sh" 2>/dev/null || true

# Change to project directory
cd "$PROJECT_ROOT" || exit 1

# Function to log with timestamp
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}

# Function to send alert
send_alert() {
    local severity=$1
    local component=$2
    local message=$3

    log "$severity [$component]: $message"
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $severity [$component]: $message" >> "$ALERT_FILE"

    # Send email on critical/warning only (not on every check)
    if [ "$severity" = "CRITICAL" ] || [ "$severity" = "WARNING" ]; then
        if command -v mail >/dev/null 2>&1; then
            echo "$message" | mail -s "[$severity] Health Check Alert: $component" "$ALERT_EMAIL"
        fi
    fi

    # Log to Laravel
    if [ -f "$PROJECT_ROOT/artisan" ]; then
        # Convert severity to lowercase for Log method (CRITICAL → critical)
        local log_method=$(echo "$severity" | tr '[:upper:]' '[:lower:]')

        # Use single-line tinker to avoid parse errors
        php artisan tinker --execute="\Log::${log_method}('Health check alert: ${component}', ['message' => '${message}']);" 2>/dev/null
    fi
}

# Check if queue worker is running
check_queue_worker() {
    if ps aux | grep "queue:work" | grep -v grep > /dev/null; then
        log "✅ Queue worker is running"
        return 0
    else
        send_alert "CRITICAL" "Queue Worker" "Queue worker is NOT running! Emails will not be sent."
        return 1
    fi
}

# Check if Laravel can boot
check_laravel_boot() {
    if php artisan --version >/dev/null 2>&1; then
        log "✅ Laravel boots successfully"
        return 0
    else
        send_alert "CRITICAL" "Laravel" "Laravel cannot boot! Check logs."
        return 1
    fi
}

# Check database connection
check_database() {
    if php artisan tinker --execute="DB::connection()->getPdo();" >/dev/null 2>&1; then
        log "✅ Database connection successful"
        return 0
    else
        send_alert "CRITICAL" "Database" "Database connection failed!"
        return 1
    fi
}

# Check pending jobs count
check_pending_jobs() {
    # Clean output: remove newlines, spaces, and extract only digits
    PENDING=$(php artisan tinker --execute="echo \DB::table('jobs')->count();" 2>/dev/null | tail -1 | tr -d '\n' | tr -d ' ' | grep -o '[0-9]*')

    # Default to 0 if empty or non-numeric
    if [ -z "$PENDING" ] || ! [[ "$PENDING" =~ ^[0-9]+$ ]]; then
        PENDING=0
        log "⚠️ Could not check pending jobs (defaulting to 0)"
    fi

    log "📊 Pending jobs: $PENDING"

    # Check CRITICAL threshold FIRST (5000+)
    if [ "$PENDING" -gt 5000 ]; then
        send_alert "CRITICAL" "Queue" "Critical pending jobs count: $PENDING. Queue is severely backed up!"
        return 1
    # Then check WARNING threshold (1000+)
    elif [ "$PENDING" -gt 1000 ]; then
        send_alert "WARNING" "Queue" "High pending jobs count: $PENDING. Queue may be backed up."
        return 0
    fi

    return 0
}

# Check failed jobs
check_failed_jobs() {
    # Count failed jobs without --json flag (not available in Laravel 9)
    FAILED=$(php artisan queue:failed 2>/dev/null | grep -c "^|" 2>/dev/null || echo "0")

    # Clean the variable: remove newlines, spaces, and extract only digits
    FAILED=$(echo "$FAILED" | tr -d '\n' | tr -d ' ' | grep -o '[0-9]*')

    # Default to 0 if empty or non-numeric
    if [ -z "$FAILED" ] || ! [[ "$FAILED" =~ ^[0-9]+$ ]]; then
        FAILED=0
    fi

    # Adjust count (subtract header rows if present)
    if [ "$FAILED" -gt 2 ]; then
        FAILED=$((FAILED - 2))
    else
        FAILED=0
    fi

    if [ "$FAILED" = "0" ]; then
        log "✅ No failed jobs"
        return 0
    fi

    log "⚠️ Failed jobs: $FAILED"

    # Check CRITICAL threshold FIRST (50+)
    if [ "$FAILED" -gt 50 ]; then
        send_alert "CRITICAL" "Failed Jobs" "Critical failed jobs count: $FAILED. Investigate immediately!"
        return 1
    # Then check WARNING threshold (10+)
    elif [ "$FAILED" -gt 10 ]; then
        send_alert "WARNING" "Failed Jobs" "High failed jobs count: $FAILED. Review and retry."
        return 0
    fi

    return 0
}

# Check recent errors in logs
check_recent_errors() {
    LOG_TODAY="$PROJECT_ROOT/storage/logs/laravel-$(date +%Y-%m-%d).log"

    if [ ! -f "$LOG_TODAY" ]; then
        log "ℹ️ No log file for today"
        return 0
    fi

    # Count critical/error entries in last 5 minutes
    ERROR_COUNT=$(grep -E "\.(CRITICAL|ERROR)" "$LOG_TODAY" | tail -100 | wc -l | tr -d ' ')

    if [ "$ERROR_COUNT" -eq 0 ]; then
        log "✅ No recent errors"
        return 0
    fi

    log "⚠️ Recent errors: $ERROR_COUNT"

    if [ "$ERROR_COUNT" -gt 10 ]; then
        RECENT_ERRORS=$(grep -E "\.(CRITICAL|ERROR)" "$LOG_TODAY" | tail -5)
        send_alert "WARNING" "Errors" "High error rate: $ERROR_COUNT errors recently. Recent: $RECENT_ERRORS"
        return 0
    elif [ "$ERROR_COUNT" -gt 50 ]; then
        send_alert "CRITICAL" "Errors" "Critical error rate: $ERROR_COUNT errors recently. Check logs immediately!"
        return 1
    fi

    return 0
}

# Main health check logic
main() {
    log "========================================="
    log "Health Check Started"
    log "========================================="

    FAILURES=0

    # Run all checks
    check_laravel_boot || ((FAILURES++))
    check_database || ((FAILURES++))
    check_queue_worker || ((FAILURES++))
    check_pending_jobs || ((FAILURES++))
    check_failed_jobs || ((FAILURES++))
    check_recent_errors || ((FAILURES++))

    log "========================================="
    if [ $FAILURES -eq 0 ]; then
        log "✅ All health checks passed"
        log "========================================="
        # Silent success (no email)
        exit 0
    else
        log "❌ Health checks failed: $FAILURES issue(s) detected"
        log "========================================="

        # Output context for email alert
        get_cron_context "$PROJECT_ROOT" 2>/dev/null || true
        cron_error "Health checks failed: $FAILURES issue(s) detected - see logs above" "health-check-monitor.sh" 2>/dev/null || echo "❌ Health check failed"

        exit 1
    fi
}

# Run the monitor
main
