#!/usr/bin/env bash

# ============================================================================
# Nginx Configuration Validator
# Validates Nginx configuration files for syntax and security best practices
# ============================================================================

set -euo pipefail

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Counters
ERRORS=0
WARNINGS=0
PASSED=0

# ============================================================================
# Helper Functions
# ============================================================================

print_header() {
    echo ""
    echo -e "${BLUE}============================================================================${NC}"
    echo -e "${BLUE}$1${NC}"
    echo -e "${BLUE}============================================================================${NC}"
    echo ""
}

print_success() {
    echo -e "${GREEN}✓ $1${NC}"
    ((PASSED++))
}

print_error() {
    echo -e "${RED}✗ $1${NC}"
    ((ERRORS++))
}

print_warning() {
    echo -e "${YELLOW}⚠ $1${NC}"
    ((WARNINGS++))
}

print_info() {
    echo -e "${BLUE}ℹ $1${NC}"
}

# ============================================================================
# Validation Functions
# ============================================================================

check_nginx_syntax() {
    print_info "Checking Nginx syntax..."

    if command -v nginx &> /dev/null; then
        if nginx -t -c "$1" 2>&1 | grep -q "syntax is ok"; then
            print_success "Nginx syntax is valid"
            return 0
        else
            print_error "Nginx syntax check failed"
            nginx -t -c "$1" 2>&1 | tail -5
            return 1
        fi
    else
        print_warning "Nginx not found - skipping syntax check"
        print_info "Install Nginx to enable syntax validation: sudo apt install nginx"
        return 0
    fi
}

check_ssl_config() {
    local config_file="$1"
    print_info "Checking SSL/TLS configuration..."

    # Check for TLS 1.2 and 1.3
    if grep -q "ssl_protocols.*TLSv1.2.*TLSv1.3" "$config_file" || \
       grep -q "ssl_protocols.*TLSv1.3.*TLSv1.2" "$config_file"; then
        print_success "Modern TLS protocols configured (TLS 1.2 & 1.3)"
    else
        print_error "TLS protocols not properly configured - should use TLSv1.2 and TLSv1.3"
    fi

    # Check for outdated protocols
    if grep -q "ssl_protocols.*SSLv" "$config_file" || \
       grep -q "ssl_protocols.*TLSv1[^.23]" "$config_file"; then
        print_error "Outdated SSL/TLS protocols detected (SSLv2/3 or TLS 1.0/1.1)"
    else
        print_success "No outdated SSL/TLS protocols found"
    fi

    # Check for OCSP stapling
    if grep -q "ssl_stapling on" "$config_file"; then
        print_success "OCSP stapling enabled"
    else
        print_warning "OCSP stapling not enabled (recommended for performance)"
    fi

    # Check for ssl_prefer_server_ciphers
    if grep -q "ssl_prefer_server_ciphers off" "$config_file"; then
        print_success "Client cipher preference enabled (recommended for TLS 1.3)"
    elif grep -q "ssl_prefer_server_ciphers on" "$config_file"; then
        print_warning "Server cipher preference enabled (consider 'off' for TLS 1.3)"
    fi
}

check_security_headers() {
    local config_file="$1"
    print_info "Checking security headers..."

    # HSTS
    if grep -q "Strict-Transport-Security" "$config_file"; then
        if grep -q "max-age=31536000" "$config_file" || grep -q "max-age=63072000" "$config_file"; then
            print_success "HSTS header configured with long max-age"
        else
            print_warning "HSTS header present but max-age might be too short"
        fi
    else
        print_error "HSTS header missing (Strict-Transport-Security)"
    fi

    # X-Frame-Options
    if grep -q "X-Frame-Options" "$config_file"; then
        print_success "X-Frame-Options header configured"
    else
        print_warning "X-Frame-Options header missing (clickjacking protection)"
    fi

    # X-Content-Type-Options
    if grep -q "X-Content-Type-Options" "$config_file"; then
        print_success "X-Content-Type-Options header configured"
    else
        print_warning "X-Content-Type-Options header missing (MIME sniffing protection)"
    fi

    # Content-Security-Policy
    if grep -q "Content-Security-Policy" "$config_file"; then
        print_success "Content-Security-Policy header configured"
    else
        print_warning "Content-Security-Policy header missing (XSS protection)"
    fi

    # Referrer-Policy
    if grep -q "Referrer-Policy" "$config_file"; then
        print_success "Referrer-Policy header configured"
    else
        print_warning "Referrer-Policy header missing"
    fi
}

check_rate_limiting() {
    local config_file="$1"
    print_info "Checking rate limiting configuration..."

    if grep -q "limit_req_zone" "$config_file"; then
        print_success "Rate limiting zones defined"

        if grep -q "limit_req.*zone=" "$config_file"; then
            print_success "Rate limiting applied in location blocks"
        else
            print_warning "Rate limiting zones defined but not applied"
        fi
    else
        print_warning "No rate limiting configured (recommended for DDoS protection)"
    fi

    if grep -q "limit_conn_zone" "$config_file"; then
        print_success "Connection limiting configured"
    else
        print_warning "Connection limiting not configured"
    fi
}

check_server_tokens() {
    local config_file="$1"
    print_info "Checking server information disclosure..."

    if grep -q "server_tokens off" "$config_file"; then
        print_success "Server tokens disabled (version hidden)"
    else
        print_error "Server tokens not disabled - Nginx version will be exposed"
    fi
}

check_https_redirect() {
    local config_file="$1"
    print_info "Checking HTTPS redirect..."

    if grep -q "return 301 https://" "$config_file"; then
        print_success "HTTP to HTTPS redirect configured"
    else
        print_warning "No HTTP to HTTPS redirect found (may be intentional)"
    fi
}

check_gzip_compression() {
    local config_file="$1"
    print_info "Checking compression configuration..."

    if grep -q "gzip on" "$config_file"; then
        print_success "Gzip compression enabled"

        if grep -q "gzip_types" "$config_file"; then
            print_success "Gzip types configured"
        else
            print_warning "Gzip types not explicitly configured"
        fi

        if grep -q "gzip_vary on" "$config_file"; then
            print_success "Gzip vary header enabled"
        fi
    else
        print_warning "Gzip compression not enabled (recommended for performance)"
    fi
}

check_logging() {
    local config_file="$1"
    print_info "Checking logging configuration..."

    if grep -q "access_log" "$config_file"; then
        print_success "Access logging configured"
    else
        print_warning "No access log configured"
    fi

    if grep -q "error_log" "$config_file"; then
        print_success "Error logging configured"
    else
        print_warning "No error log configured"
    fi
}

check_proxy_headers() {
    local config_file="$1"

    # Only check if proxy_pass is present
    if grep -q "proxy_pass" "$config_file"; then
        print_info "Checking proxy headers (config contains proxy_pass)..."

        local required_headers=("X-Real-IP" "X-Forwarded-For" "X-Forwarded-Proto" "Host")
        local missing_headers=()

        for header in "${required_headers[@]}"; do
            if grep -q "proxy_set_header $header" "$config_file"; then
                print_success "Proxy header '$header' configured"
            else
                missing_headers+=("$header")
            fi
        done

        if [ ${#missing_headers[@]} -gt 0 ]; then
            print_warning "Missing proxy headers: ${missing_headers[*]}"
        fi
    fi
}

check_buffer_overflow_protection() {
    local config_file="$1"
    print_info "Checking buffer overflow protection..."

    local has_buffers=false

    if grep -q "client_body_buffer_size" "$config_file"; then
        has_buffers=true
    fi

    if grep -q "client_max_body_size" "$config_file"; then
        has_buffers=true
    fi

    if grep -q "client_header_buffer_size" "$config_file"; then
        has_buffers=true
    fi

    if [ "$has_buffers" = true ]; then
        print_success "Buffer sizes configured"
    else
        print_warning "Buffer sizes not explicitly configured"
    fi
}

check_timeouts() {
    local config_file="$1"
    print_info "Checking timeout configuration..."

    if grep -q "client_body_timeout\|client_header_timeout" "$config_file"; then
        print_success "Client timeouts configured"
    else
        print_warning "Client timeouts not explicitly configured"
    fi

    if grep -q "keepalive_timeout" "$config_file"; then
        print_success "Keepalive timeout configured"
    fi
}

# ============================================================================
# Main Script
# ============================================================================

print_header "Nginx Configuration Validator"

# Check if config file is provided
if [ $# -eq 0 ]; then
    echo "Usage: $0 <nginx-config-file>"
    echo ""
    echo "Example:"
    echo "  $0 /etc/nginx/sites-available/example.com.conf"
    echo "  $0 ./my-nginx.conf"
    echo ""
    exit 1
fi

CONFIG_FILE="$1"

# Check if file exists
if [ ! -f "$CONFIG_FILE" ]; then
    print_error "Configuration file not found: $CONFIG_FILE"
    exit 1
fi

print_info "Validating: $CONFIG_FILE"
echo ""

# Run all checks
check_nginx_syntax "$CONFIG_FILE"
echo ""

check_ssl_config "$CONFIG_FILE"
echo ""

check_security_headers "$CONFIG_FILE"
echo ""

check_rate_limiting "$CONFIG_FILE"
echo ""

check_server_tokens "$CONFIG_FILE"
echo ""

check_https_redirect "$CONFIG_FILE"
echo ""

check_gzip_compression "$CONFIG_FILE"
echo ""

check_logging "$CONFIG_FILE"
echo ""

check_proxy_headers "$CONFIG_FILE"
echo ""

check_buffer_overflow_protection "$CONFIG_FILE"
echo ""

check_timeouts "$CONFIG_FILE"
echo ""

# ============================================================================
# Summary
# ============================================================================

print_header "Validation Summary"

echo "Configuration File: $CONFIG_FILE"
echo ""
echo -e "${GREEN}Passed Checks:  $PASSED${NC}"
echo -e "${YELLOW}Warnings:       $WARNINGS${NC}"
echo -e "${RED}Errors:         $ERRORS${NC}"
echo ""

if [ $ERRORS -eq 0 ] && [ $WARNINGS -eq 0 ]; then
    print_success "Configuration looks great! All checks passed."
    echo ""
    echo "Next steps:"
    echo "  1. sudo nginx -t"
    echo "  2. sudo systemctl reload nginx"
    exit 0
elif [ $ERRORS -eq 0 ]; then
    print_success "Configuration is valid with $WARNINGS warnings."
    echo ""
    echo "Consider addressing the warnings above for better security and performance."
    echo ""
    echo "Next steps:"
    echo "  1. sudo nginx -t"
    echo "  2. sudo systemctl reload nginx"
    exit 0
else
    print_error "Configuration has $ERRORS error(s) and $WARNINGS warning(s)."
    echo ""
    echo "Please fix the errors above before deploying."
    exit 1
fi
