#!/bin/bash
# Script Name: mpdiag.sh
# Description: MultiPortal installation diagnostics script
# Purpose: Verify MultiPortal installation integrity and health
# Author: Matthew Wood
# Version: 1.0
# Usage: ./mpdiag.sh [options]

set -euo pipefail
IFS=$'\n\t'

# Variables
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LOG_FILE="$SCRIPT_DIR/mpdiag_$(date +%Y%m%d_%H%M%S).log"
SUMMARY_FILE="$SCRIPT_DIR/mpdiag_summary_$(date +%Y%m%d_%H%M%S).txt"
VERBOSE=false
FIX_MODE=false
FQDN=""
ISSUES_FOUND=0

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

# Logging functions
log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') [LOG] $1" | tee -a "$LOG_FILE"
}

log_success() {
    echo -e "${GREEN}$(date '+%Y-%m-%d %H:%M:%S') [SUCCESS] $1${NC}" | tee -a "$LOG_FILE"
}

log_error() {
    echo -e "${RED}$(date '+%Y-%m-%d %H:%M:%S') [ERROR] $1${NC}" | tee -a "$LOG_FILE"
    ((ISSUES_FOUND++))
}

log_warning() {
    echo -e "${YELLOW}$(date '+%Y-%m-%d %H:%M:%S') [WARNING] $1${NC}" | tee -a "$LOG_FILE"
}

log_info() {
    echo -e "${BLUE}$(date '+%Y-%m-%d %H:%M:%S') [INFO] $1${NC}" | tee -a "$LOG_FILE"
}

# Usage function
usage() {
    cat << EOF
MultiPortal Diagnostics Script

Usage: $0 [OPTIONS]

OPTIONS:
    -f, --fqdn <domain>     Specify the FQDN (auto-detected if not provided)
    -v, --verbose           Enable verbose output
    -r, --repair            Attempt to fix detected issues
    -h, --help              Show this help message

EXAMPLES:
    $0                      Run basic diagnostics
    $0 -f example.com       Run diagnostics for specific domain
    $0 -v -r                Run verbose diagnostics with repair mode

EOF
}

# Parse command line arguments
parse_args() {
    while [[ $# -gt 0 ]]; do
        case $1 in
            -f|--fqdn)
                FQDN="$2"
                shift 2
                ;;
            -v|--verbose)
                VERBOSE=true
                shift
                ;;
            -r|--repair)
                FIX_MODE=true
                shift
                ;;
            -h|--help)
                usage
                exit 0
                ;;
            *)
                echo "Unknown option: $1"
                usage
                exit 1
                ;;
        esac
    done
}

# Get FQDN from installation
get_fqdn() {
    if [[ -z "$FQDN" ]]; then
        # Try to get from /var/www directory
        for dir in /var/www/*; do
            if [[ -d "$dir" && -f "$dir/.env" && "$dir" != "/var/www/html" ]]; then
                FQDN=$(basename "$dir")
                break
            fi
        done
    fi
    
    if [[ -z "$FQDN" ]]; then
        log_error "Could not determine FQDN. Please specify with -f option"
        exit 1
    fi
    
    WEB_DIR="/var/www/$FQDN"
    ENV_FILE="$WEB_DIR/.env"
}

# Check if running as root
check_root() {
    if [[ $EUID -ne 0 ]]; then
        log_error "This script must be run as root"
        exit 1
    fi
}

# System information
print_system_info() {
    log_info "=== SYSTEM INFORMATION ==="
    log "Hostname: $(hostname)"
    log "OS: $(cat /etc/os-release | grep PRETTY_NAME | cut -d'"' -f2)"
    log "Kernel: $(uname -r)"
    log "Architecture: $(uname -m)"
    log "CPU Cores: $(nproc)"
    log "Total Memory: $(free -h | awk '/^Mem:/ {print $2}')"
    log "Disk Usage: $(df -h / | awk 'NR==2 {print $3 " / " $2 " (" $5 " used)"}')"
    log "FQDN: $FQDN"
    log "Web Directory: $WEB_DIR"
    echo ""
}

# Check MultiPortal installation
check_installation() {
    log_info "=== CHECKING MULTIPORTAL INSTALLATION ==="
    
    # Check if web directory exists
    if [[ ! -d "$WEB_DIR" ]]; then
        log_error "Web directory not found: $WEB_DIR"
        return 1
    else
        log_success "Web directory exists: $WEB_DIR"
    fi
    
    # Check essential files
    local essential_files=(
        "$WEB_DIR/yii"
        "$WEB_DIR/.env"
        "$WEB_DIR/backend/web/index.php"
        "$WEB_DIR/common/config/main-local.php"
    )
    
    for file in "${essential_files[@]}"; do
        if [[ ! -f "$file" ]]; then
            log_error "Essential file missing: $file"
        else
            log_success "Essential file exists: $file"
        fi
    done
    
    # Check directory permissions
    local web_owner=$(stat -c '%U' "$WEB_DIR")
    local web_group=$(stat -c '%G' "$WEB_DIR")
    
    if [[ "$web_owner" == "www-data" ]] || [[ "$web_owner" == "caddy" ]]; then
        log_success "Web directory owner is correct: $web_owner"
    else
        log_error "Web directory owner is incorrect: $web_owner (should be www-data or caddy)"
    fi
    
    echo ""
}

# Check PHP configuration
check_php() {
    log_info "=== CHECKING PHP CONFIGURATION ==="
    
    # Check PHP version
    if command -v php &> /dev/null; then
        local php_version=$(php -v | head -n 1 | awk '{print $2}')
        log "PHP Version: $php_version"
        
        if [[ "$php_version" =~ ^8\.2 ]]; then
            log_success "PHP version is correct"
        else
            log_error "PHP version is incorrect (requires 8.2.x)"
        fi
    else
        log_error "PHP is not installed"
    fi
    
    # Check PHP-FPM
    if systemctl is-active --quiet php8.2-fpm 2>/dev/null || systemctl is-active --quiet php-fpm 2>/dev/null; then
        log_success "PHP-FPM is running"
    else
        log_error "PHP-FPM is not running"
    fi
    
    # Check PHP extensions
    local required_extensions=("curl" "gd" "mbstring" "mysqli" "xml" "zip")
    for ext in "${required_extensions[@]}"; do
        if php -m | grep -qi "^$ext$"; then
            log_success "PHP extension '$ext' is installed"
        else
            log_error "PHP extension '$ext' is missing"
        fi
    done
    
    # Check IonCube
    if php -m | grep -qi "ionCube"; then
        log_success "IonCube loader is installed"
    else
        log_error "IonCube loader is not installed"
    fi
    
    echo ""
}

# Check database
check_database() {
    log_info "=== CHECKING DATABASE ==="
    
    # Check MariaDB service
    if systemctl is-active --quiet mariadb; then
        log_success "MariaDB service is running"
    else
        log_error "MariaDB service is not running"
        return 1
    fi
    
    # Get database credentials from .env
    if [[ -f "$ENV_FILE" ]]; then
        local db_host=$(grep '^DB_HOST=' "$ENV_FILE" | cut -d'=' -f2)
        local db_name=$(grep '^DB_NAME=' "$ENV_FILE" | cut -d'=' -f2)
        local db_user=$(grep '^DB_USER=' "$ENV_FILE" | cut -d'=' -f2)
        local db_pass=$(grep '^DB_PASS=' "$ENV_FILE" | cut -d'=' -f2)
        
        # Test database connection
        if mysql -h"$db_host" -u"$db_user" -p"$db_pass" -e "SELECT 1;" "$db_name" &>/dev/null; then
            log_success "Database connection successful"
            
            # Check tables
            local table_count=$(mysql -h"$db_host" -u"$db_user" -p"$db_pass" -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='$db_name';" -s -N)
            log "Database tables: $table_count"
            
            if [[ $table_count -gt 0 ]]; then
                log_success "Database has tables"
            else
                log_error "Database appears to be empty"
            fi
        else
            log_error "Database connection failed"
        fi
        
        # Check Galera cluster status if configured
        if mysql -u root -e "SHOW GLOBAL STATUS LIKE 'wsrep_cluster_size';" &>/dev/null; then
            local cluster_size=$(mysql -u root -e "SHOW GLOBAL STATUS LIKE 'wsrep_cluster_size';" -s -N | awk '{print $2}')
            if [[ -n "$cluster_size" ]]; then
                log_info "Galera cluster size: $cluster_size"
                if [[ $cluster_size -gt 0 ]]; then
                    log_success "Galera cluster is active"
                else
                    log_warning "Galera cluster size is 0"
                fi
            fi
        fi
    else
        log_error ".env file not found"
    fi
    
    echo ""
}

# Check SSL certificates
check_ssl() {
    log_info "=== CHECKING SSL CERTIFICATES ==="
    
    # Check Caddy configuration
    if [[ -f "/etc/caddy/Caddyfile" ]]; then
        log_success "Caddyfile exists"
        
        # Check if using custom certificates
        if grep -q "/var/lib/caddy/sslcer.cer" /etc/caddy/Caddyfile; then
            log_info "Using custom SSL certificates"
            
            if [[ -f "/var/lib/caddy/sslcer.cer" && -f "/var/lib/caddy/sslkey.key" ]]; then
                log_success "Custom SSL certificate files exist"
                
                # Check certificate validity
                if openssl x509 -in /var/lib/caddy/sslcer.cer -noout -checkend 0 &>/dev/null; then
                    log_success "SSL certificate is valid"
                    
                    # Show expiration date
                    local expiry=$(openssl x509 -in /var/lib/caddy/sslcer.cer -noout -enddate | cut -d'=' -f2)
                    log_info "Certificate expires: $expiry"
                else
                    log_error "SSL certificate has expired or is invalid"
                fi
            else
                log_error "Custom SSL certificate files not found"
            fi
        else
            log_info "Using Let's Encrypt (automatic certificates)"
            
            # Check Caddy certificate storage
            if [[ -d "/var/lib/caddy/.local/share/caddy/certificates" ]]; then
                local cert_count=$(find /var/lib/caddy/.local/share/caddy/certificates -name "*.crt" 2>/dev/null | wc -l)
                if [[ $cert_count -gt 0 ]]; then
                    log_success "Let's Encrypt certificates found: $cert_count"
                else
                    log_warning "No Let's Encrypt certificates found"
                fi
            fi
        fi
    else
        log_error "Caddyfile not found"
    fi
    
    echo ""
}

# Check services
check_services() {
    log_info "=== CHECKING SERVICES ==="
    
    local services=("caddy" "mariadb" "multiportal")
    
    # Add PHP-FPM service based on distribution
    if systemctl list-unit-files | grep -q "php8.2-fpm.service"; then
        services+=("php8.2-fpm")
    elif systemctl list-unit-files | grep -q "php-fpm.service"; then
        services+=("php-fpm")
    fi
    
    for service in "${services[@]}"; do
        if systemctl is-active --quiet "$service"; then
            log_success "$service is running"
            
            if [[ "$VERBOSE" == true ]]; then
                systemctl status "$service" --no-pager | head -n 5
            fi
        else
            log_error "$service is not running"
            
            if [[ "$FIX_MODE" == true ]]; then
                log_info "Attempting to start $service..."
                if systemctl start "$service"; then
                    log_success "$service started successfully"
                else
                    log_error "Failed to start $service"
                fi
            fi
        fi
    done
    
    # Check if services are enabled
    log_info "Checking service auto-start status..."
    for service in "${services[@]}"; do
        if systemctl is-enabled --quiet "$service" 2>/dev/null; then
            log_success "$service is enabled (will start on boot)"
        else
            log_warning "$service is not enabled"
            
            if [[ "$FIX_MODE" == true ]]; then
                log_info "Enabling $service..."
                systemctl enable "$service"
            fi
        fi
    done
    
    echo ""
}

# Check Node.js and PM2
check_nodejs() {
    log_info "=== CHECKING NODE.JS AND PM2 ==="
    
    # Check Node.js
    if command -v node &> /dev/null; then
        local node_version=$(node -v)
        log_success "Node.js is installed: $node_version"
    else
        log_error "Node.js is not installed"
    fi
    
    # Check PM2
    if command -v pm2 &> /dev/null; then
        log_success "PM2 is installed"
        
        # Check PM2 processes
        local pm2_count=$(pm2 list --silent | grep -c "online" || echo "0")
        if [[ $pm2_count -gt 0 ]]; then
            log_success "PM2 has $pm2_count running process(es)"
            
            if [[ "$VERBOSE" == true ]]; then
                pm2 list
            fi
        else
            log_warning "No PM2 processes are running"
        fi
        
        # Check PM2 startup
        if systemctl is-enabled --quiet pm2-root 2>/dev/null; then
            log_success "PM2 startup is configured"
        else
            log_warning "PM2 startup is not configured"
            
            if [[ "$FIX_MODE" == true ]]; then
                log_info "Configuring PM2 startup..."
                pm2 startup systemd -u root --hp /root
                pm2 save
            fi
        fi
    else
        log_error "PM2 is not installed"
        
        if [[ "$FIX_MODE" == true ]]; then
            log_info "Installing PM2..."
            npm install -g pm2
        fi
    fi
    
    echo ""
}

# Check cron jobs
check_cron() {
    log_info "=== CHECKING CRON JOBS ==="
    
    # Check if cron job exists
    if crontab -l 2>/dev/null | grep -q "$WEB_DIR/yii cron"; then
        log_success "MultiPortal cron job is configured"
        
        if [[ "$VERBOSE" == true ]]; then
            log_info "Cron entries:"
            crontab -l | grep "$WEB_DIR"
        fi
    else
        log_warning "MultiPortal cron job is not configured"
        
        if [[ "$FIX_MODE" == true ]]; then
            log_info "Adding cron job..."
            (crontab -l 2>/dev/null; echo "*/5 * * * * $WEB_DIR/yii cron") | crontab -
            log_success "Cron job added"
        fi
    fi
    
    echo ""
}

# Run post-installation scripts
run_post_scripts() {
    log_info "=== RUNNING POST-INSTALLATION SCRIPTS ==="
    
    cd "$WEB_DIR" || {
        log_error "Cannot change to web directory"
        return 1
    }
    
    # Run migration
    log_info "Running database migrations..."
    if ./yii migrate --interactive=0 2>&1 | tee -a "$LOG_FILE"; then
        log_success "Migrations completed"
    else
        log_error "Migration failed"
    fi
    
    # Update routes
    log_info "Updating routes..."
    if ./yii server/update-routes 2>&1 | tee -a "$LOG_FILE"; then
        log_success "Routes updated"
    else
        log_error "Route update failed"
    fi
    
    # Run post-update
    log_info "Running post-update..."
    if ./yii updater/post-update 2>&1 | tee -a "$LOG_FILE"; then
        log_success "Post-update completed"
    else
        log_error "Post-update failed"
    fi
    
    # Run cron manually
    log_info "Running cron job manually..."
    if ./yii cron 2>&1 | tee -a "$LOG_FILE"; then
        log_success "Cron job executed"
    else
        log_error "Cron job failed"
    fi
    
    echo ""
}

# Check for hidden system files
check_hidden_files() {
    log_info "=== CHECKING FOR HIDDEN SYSTEM FILES ==="
    
    local runtime_dir="$WEB_DIR/common/runtime"
    
    if [[ -d "$runtime_dir" ]]; then
        local hidden_files=$(ls -la "$runtime_dir" | grep '\.sys_' | wc -l)
        
        if [[ $hidden_files -gt 0 ]]; then
            log_info "Found $hidden_files hidden system file(s)"
            
            if [[ "$VERBOSE" == true ]]; then
                ls -la "$runtime_dir" | grep '\.sys_'
            fi
        else
            log_success "No hidden system files found"
        fi
    else
        log_error "Runtime directory not found: $runtime_dir"
    fi
    
    echo ""
}

# Check web accessibility
check_web_access() {
    log_info "=== CHECKING WEB ACCESSIBILITY ==="
    
    # Check HTTPS
    if curl -s -o /dev/null -w "%{http_code}" "https://$FQDN" | grep -q "200"; then
        log_success "HTTPS access is working"
    else
        log_warning "HTTPS access failed (this may be normal if using HTTP only)"
    fi
    
    # Check WebSocket port
    if nc -zv localhost 8081 &>/dev/null; then
        log_success "WebSocket port (8081) is open"
    else
        log_warning "WebSocket port (8081) is not accessible"
    fi
    
    echo ""
}

# Generate summary report
generate_summary() {
    log_info "=== GENERATING SUMMARY REPORT ==="
    
    {
        echo "MultiPortal Diagnostics Summary"
        echo "==============================="
        echo "Generated: $(date)"
        echo "FQDN: $FQDN"
        echo "Issues Found: $ISSUES_FOUND"
        echo ""
        echo "For detailed information, see: $LOG_FILE"
    } > "$SUMMARY_FILE"
    
    if [[ $ISSUES_FOUND -eq 0 ]]; then
        log_success "All checks passed! MultiPortal installation appears healthy."
    else
        log_warning "Found $ISSUES_FOUND issue(s). Review the log for details."
    fi
    
    echo ""
    log_info "Summary saved to: $SUMMARY_FILE"
    log_info "Full log saved to: $LOG_FILE"
}

# Main execution
main() {
    clear
    echo "=================================="
    echo "MultiPortal Diagnostics Script"
    echo "=================================="
    echo ""
    
    # Parse arguments
    parse_args "$@"
    
    # Check root
    check_root
    
    # Get FQDN
    get_fqdn
    
    # Initialize log
    log_info "Starting MultiPortal diagnostics for $FQDN"
    echo ""
    
    # Run all checks
    print_system_info
    check_installation
    check_php
    check_database
    check_ssl
    check_services
    check_nodejs
    check_cron
    
    # Run post scripts if requested
    if [[ "$FIX_MODE" == true ]]; then
        run_post_scripts
    fi
    
    check_hidden_files
    check_web_access
    
    # Generate summary
    generate_summary
}

# Run main function
main "$@"
