#!/bin/bash

# =========================================================================
# fix-db-connection.sh
# =========================================================================
# Description: This script checks and fixes database connection issues on the
# staging server that are causing E2E test failures. It specifically addresses
# the "Access denied for user 'root'@'localhost'" error by verifying and
# correcting database configuration settings in local scripts and configurations.
#
# Usage: ./bin/fix-db-connection.sh [--verbose] [--dry-run]
#
# Options:
#   --verbose     Show detailed output during execution
#   --dry-run     Show what would be done without making changes
#
# Author: Roo Code
# Date: April 24, 2025
# =========================================================================

# Get absolute path to this script's directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# Load environment variables
ENV_FILE="$SCRIPT_DIR/../.env"
if [ ! -f "$ENV_FILE" ]; then
    echo "Error: .env file not found at: $ENV_FILE"
    exit 1
fi

source "$ENV_FILE"

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

# Default options
VERBOSE=false
DRY_RUN=false

# Parse command line arguments
for arg in "$@"; do
    case $arg in
        --verbose)
            VERBOSE=true
            shift
            ;;
        --dry-run)
            DRY_RUN=true
            shift
            ;;
        --help)
            echo "Usage: $0 [--verbose] [--dry-run]"
            echo ""
            echo "Options:"
            echo "  --verbose     Show detailed output during execution"
            echo "  --dry-run     Show what would be done without making changes"
            echo "  --help        Show this help message"
            exit 0
            ;;
    esac
done

# Function to check if a command was successful
check_status() {
    if [ $? -eq 0 ]; then
        echo -e "${GREEN}✓ $1${NC}"
        return 0
    else
        echo -e "${RED}✗ $1${NC}"
        return 1
    fi
}

# Function to log verbose output
log_verbose() {
    if [ "$VERBOSE" = true ]; then
        echo -e "${BLUE}[INFO] $1${NC}"
    fi
}

# Function to log error messages
log_error() {
    echo -e "${RED}[ERROR] $1${NC}"
}

# Function to log warning messages
log_warning() {
    echo -e "${YELLOW}[WARNING] $1${NC}"
}

# Function to log success messages
log_success() {
    echo -e "${GREEN}[SUCCESS] $1${NC}"
}

# Function to check SSH connection
check_ssh_connection() {
    log_verbose "Testing SSH connection to staging server..."
    if ! sshpass -p "$UPSKILL_STAGING_PASS" ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 "$UPSKILL_STAGING_SSH_USER@$UPSKILL_STAGING_IP" "echo 'SSH connection successful'" > /dev/null 2>&1; then
        log_error "Cannot connect to staging server. Please check your SSH credentials and network connection."
        exit 1
    fi
    log_verbose "SSH connection successful."
}

# Function to check database connection from staging server
check_remote_db_connection() {
    log_verbose "Testing database connection from staging server..."
    
    # Construct the MySQL command to run on the staging server
    local mysql_cmd="mysql -h localhost -u $UPSKILL_STAGING_DB_USER -p'$UPSKILL_STAGING_DB_PASSWORD' $UPSKILL_STAGING_DB_NAME -e 'SELECT 1;' 2>&1"
    
    # Execute the command on the staging server
    local result
    result=$(sshpass -p "$UPSKILL_STAGING_PASS" ssh -o StrictHostKeyChecking=no "$UPSKILL_STAGING_SSH_USER@$UPSKILL_STAGING_IP" "$mysql_cmd")
    
    # Check if the command was successful
    if [[ $result == *"1"* ]]; then
        log_success "Database connection from staging server successful."
        return 0
    else
        log_error "Database connection from staging server failed: $result"
        return 1
    fi
}

# Function to check database connection from local machine
check_local_db_connection() {
    log_verbose "Testing database connection from local machine..."
    
    # Construct the MySQL command to run locally
    local mysql_cmd="mysql -h $UPSKILL_STAGING_IP -u $UPSKILL_STAGING_DB_USER -p'$UPSKILL_STAGING_DB_PASSWORD' $UPSKILL_STAGING_DB_NAME -e 'SELECT 1;' 2>&1"
    
    # Execute the command locally
    local result
    result=$(eval "$mysql_cmd")
    
    # Check if the command was successful
    if [[ $result == *"1"* ]]; then
        log_success "Database connection from local machine successful."
        return 0
    else
        log_warning "Database connection from local machine failed: $result"
        log_verbose "This is expected if the database is not accessible from outside the server."
        return 1
    fi
}

# Function to check WordPress database configuration
check_wp_config() {
    log_verbose "Checking WordPress database configuration on staging server..."
    
    # Get the database configuration from wp-config.php
    local wp_config_cmd="cd $UPSKILL_STAGING_PATH && grep -E \"^define\\('DB_[A-Z]+', '.*'\\);\" wp-config.php"
    local wp_config
    wp_config=$(sshpass -p "$UPSKILL_STAGING_PASS" ssh -o StrictHostKeyChecking=no "$UPSKILL_STAGING_SSH_USER@$UPSKILL_STAGING_IP" "$wp_config_cmd")
    
    # Extract database settings
    local db_name=$(echo "$wp_config" | grep "DB_NAME" | sed -E "s/define\('DB_NAME', '(.*)'\);/\1/")
    local db_user=$(echo "$wp_config" | grep "DB_USER" | sed -E "s/define\('DB_USER', '(.*)'\);/\1/")
    local db_password=$(echo "$wp_config" | grep "DB_PASSWORD" | sed -E "s/define\('DB_PASSWORD', '(.*)'\);/\1/")
    local db_host=$(echo "$wp_config" | grep "DB_HOST" | sed -E "s/define\('DB_HOST', '(.*)'\);/\1/")
    
    echo "Current WordPress database configuration on staging server:"
    echo "  DB_NAME: $db_name"
    echo "  DB_USER: $db_user"
    echo "  DB_HOST: $db_host"
    echo "  DB_PASSWORD: [HIDDEN]"
    
    # Check if the configuration matches the environment variables
    if [ "$db_name" != "$UPSKILL_STAGING_DB_NAME" ]; then
        log_warning "DB_NAME in wp-config.php ($db_name) does not match .env file ($UPSKILL_STAGING_DB_NAME)"
    fi
    
    if [ "$db_user" != "$UPSKILL_STAGING_DB_USER" ]; then
        log_warning "DB_USER in wp-config.php ($db_user) does not match .env file ($UPSKILL_STAGING_DB_USER)"
    fi
    
    if [ "$db_password" != "$UPSKILL_STAGING_DB_PASSWORD" ]; then
        log_warning "DB_PASSWORD in wp-config.php does not match .env file"
    fi
    
    # Return the extracted values
    echo "$db_name|$db_user|$db_password|$db_host"
}

# Function to check for hardcoded database credentials in test files
check_test_files() {
    log_verbose "Checking for hardcoded database credentials in test files..."
    
    # Search for 'root' user in test files
    local search_cmd="find $SCRIPT_DIR/.. -type f -name \"*.php\" -o -name \"*.js\" -o -name \"*.ts\" | xargs grep -l \"'root'\\|\\\"root\\\"\" 2>/dev/null || true"
    local files
    files=$(eval "$search_cmd")
    
    if [ -n "$files" ]; then
        echo "Found files with potential hardcoded 'root' database user:"
        echo "$files"
        return 0
    else
        log_verbose "No files with hardcoded 'root' database user found."
        return 1
    fi
}

# Function to check Playwright configuration
check_playwright_config() {
    log_verbose "Checking Playwright configuration..."
    
    local config_file="$SCRIPT_DIR/../playwright.config.ts"
    
    if [ ! -f "$config_file" ]; then
        log_warning "Playwright configuration file not found: $config_file"
        return 1
    fi
    
    # Check for database configuration in Playwright config
    local db_config
    db_config=$(grep -A 10 "database\|DB_" "$config_file" 2>/dev/null || true)
    
    if [ -n "$db_config" ]; then
        echo "Found database configuration in Playwright config:"
        echo "$db_config"
        return 0
    else
        log_verbose "No database configuration found in Playwright config."
        return 1
    fi
}

# Function to check E2E test files for database connection issues
check_e2e_tests() {
    log_verbose "Checking E2E test files for database connection issues..."
    
    local tests_dir="$SCRIPT_DIR/../tests"
    
    if [ ! -d "$tests_dir" ]; then
        log_warning "Tests directory not found: $tests_dir"
        return 1
    fi
    
    # Search for database connection code in E2E test files
    local search_cmd="find $tests_dir -type f -name \"*.spec.ts\" -o -name \"*.spec.js\" | xargs grep -l \"mysql\\|database\\|connection\\|root\" 2>/dev/null || true"
    local files
    files=$(eval "$search_cmd")
    
    if [ -n "$files" ]; then
        echo "Found E2E test files with potential database connection code:"
        echo "$files"
        return 0
    else
        log_verbose "No E2E test files with database connection code found."
        return 1
    fi
}

# Function to fix database connection in a file
fix_file() {
    local file="$1"
    local backup_file="${file}.bak.$(date +%Y%m%d%H%M%S)"
    
    log_verbose "Fixing database connection in file: $file"
    
    # Create a backup of the file
    if [ "$DRY_RUN" = true ]; then
        log_verbose "Would create backup of $file to $backup_file"
    else
        cp "$file" "$backup_file"
        check_status "Created backup of $file"
    fi
    
    # Replace 'root' with the correct database user
    if [ "$DRY_RUN" = true ]; then
        log_verbose "Would replace 'root' with '$UPSKILL_STAGING_DB_USER' in $file"
    else
        sed -i.tmp "s/'root'/'$UPSKILL_STAGING_DB_USER'/g" "$file"
        sed -i.tmp "s/\"root\"/\"$UPSKILL_STAGING_DB_USER\"/g" "$file"
        rm -f "${file}.tmp"
        check_status "Replaced 'root' with '$UPSKILL_STAGING_DB_USER' in $file"
    fi
    
    # Replace hardcoded password if found
    if [ "$DRY_RUN" = true ]; then
        log_verbose "Would replace hardcoded password with '$UPSKILL_STAGING_DB_PASSWORD' in $file"
    else
        # This is a simplified approach; in a real scenario, you'd need a more sophisticated pattern matching
        sed -i.tmp "s/'password'/'$UPSKILL_STAGING_DB_PASSWORD'/g" "$file"
        sed -i.tmp "s/\"password\"/\"$UPSKILL_STAGING_DB_PASSWORD\"/g" "$file"
        rm -f "${file}.tmp"
        check_status "Replaced hardcoded password in $file"
    fi
}

# Function to check and fix wp-tests-config.php
check_wp_tests_config() {
    log_verbose "Checking wp-tests-config.php..."
    
    local config_file="$SCRIPT_DIR/../wp-tests-config.php"
    
    if [ ! -f "$config_file" ]; then
        log_warning "wp-tests-config.php not found: $config_file"
        return 1
    fi
    
    # Check for 'root' user in wp-tests-config.php
    local root_user
    root_user=$(grep -E "define\\( *'DB_USER', *'root' *\\)" "$config_file" 2>/dev/null || true)
    
    if [ -n "$root_user" ]; then
        echo "Found 'root' user in wp-tests-config.php:"
        echo "$root_user"
        
        # Fix wp-tests-config.php
        if [ "$DRY_RUN" = true ]; then
            log_verbose "Would update wp-tests-config.php to use '$UPSKILL_STAGING_DB_USER' instead of 'root'"
        else
            local backup_file="${config_file}.bak.$(date +%Y%m%d%H%M%S)"
            cp "$config_file" "$backup_file"
            sed -i.tmp "s/define( *'DB_USER', *'root' *)/define( 'DB_USER', '$UPSKILL_STAGING_DB_USER' )/g" "$config_file"
            sed -i.tmp "s/define( *'DB_PASSWORD', *'[^']*' *)/define( 'DB_PASSWORD', '$UPSKILL_STAGING_DB_PASSWORD' )/g" "$config_file"
            rm -f "${config_file}.tmp"
            check_status "Updated wp-tests-config.php to use correct database credentials"
        fi
        return 0
    else
        log_verbose "No 'root' user found in wp-tests-config.php."
        return 1
    fi
}

# Function to check and fix wp-tests-config-staging.php
check_wp_tests_config_staging() {
    log_verbose "Checking wp-tests-config-staging.php..."
    
    local config_file="$SCRIPT_DIR/wp-tests-config-staging.php"
    
    if [ ! -f "$config_file" ]; then
        log_warning "wp-tests-config-staging.php not found: $config_file"
        return 1
    fi
    
    # Check for 'root' user in wp-tests-config-staging.php
    local root_user
    root_user=$(grep -E "define\\( *'DB_USER', *'root' *\\)" "$config_file" 2>/dev/null || true)
    
    if [ -n "$root_user" ]; then
        echo "Found 'root' user in wp-tests-config-staging.php:"
        echo "$root_user"
        
        # Fix wp-tests-config-staging.php
        if [ "$DRY_RUN" = true ]; then
            log_verbose "Would update wp-tests-config-staging.php to use '$UPSKILL_STAGING_DB_USER' instead of 'root'"
        else
            local backup_file="${config_file}.bak.$(date +%Y%m%d%H%M%S)"
            cp "$config_file" "$backup_file"
            sed -i.tmp "s/define( *'DB_USER', *'root' *)/define( 'DB_USER', '$UPSKILL_STAGING_DB_USER' )/g" "$config_file"
            sed -i.tmp "s/define( *'DB_PASSWORD', *'[^']*' *)/define( 'DB_PASSWORD', '$UPSKILL_STAGING_DB_PASSWORD' )/g" "$config_file"
            rm -f "${config_file}.tmp"
            check_status "Updated wp-tests-config-staging.php to use correct database credentials"
        fi
        return 0
    else
        log_verbose "No 'root' user found in wp-tests-config-staging.php."
        return 1
    fi
}

# Main function
main() {
    echo "=== Database Connection Fix Script ==="
    echo "Staging Server: $UPSKILL_STAGING_IP"
    echo "Database: $UPSKILL_STAGING_DB_NAME"
    echo "User: $UPSKILL_STAGING_DB_USER"
    echo "==============================="
    
    if [ "$DRY_RUN" = true ]; then
        echo -e "${YELLOW}Running in dry-run mode. No changes will be made.${NC}"
    fi
    
    # Step 1: Check SSH connection
    echo -e "\n${YELLOW}Step 1: Checking SSH connection...${NC}"
    check_ssh_connection
    check_status "SSH connection check"
    
    # Step 2: Check remote database connection
    echo -e "\n${YELLOW}Step 2: Checking database connection from staging server...${NC}"
    check_remote_db_connection
    check_status "Remote database connection check"
    
    # Step 3: Check WordPress configuration
    echo -e "\n${YELLOW}Step 3: Checking WordPress configuration...${NC}"
    check_wp_config
    check_status "WordPress configuration check"
    
    # Step 4: Check test files for hardcoded credentials
    echo -e "\n${YELLOW}Step 4: Checking test files for hardcoded credentials...${NC}"
    if check_test_files; then
        echo "Found files with potential hardcoded credentials. Fixing..."
        
        # Fix each file
        for file in $(find $SCRIPT_DIR/.. -type f -name "*.php" -o -name "*.js" -o -name "*.ts" | xargs grep -l "'root'\\|\"root\"" 2>/dev/null || true); do
            fix_file "$file"
        done
    else
        echo "No files with hardcoded 'root' credentials found."
    fi
    
    # Step 5: Check and fix wp-tests-config.php
    echo -e "\n${YELLOW}Step 5: Checking and fixing wp-tests-config.php...${NC}"
    check_wp_tests_config
    
    # Step 6: Check and fix wp-tests-config-staging.php
    echo -e "\n${YELLOW}Step 6: Checking and fixing wp-tests-config-staging.php...${NC}"
    check_wp_tests_config_staging
    
    # Step 7: Check Playwright configuration
    echo -e "\n${YELLOW}Step 7: Checking Playwright configuration...${NC}"
    check_playwright_config
    
    # Step 8: Check E2E test files
    echo -e "\n${YELLOW}Step 8: Checking E2E test files...${NC}"
    check_e2e_tests
    
    # Step 9: Verify fixes
    echo -e "\n${YELLOW}Step 9: Verifying fixes...${NC}"
    if [ "$DRY_RUN" = false ]; then
        # Check remote database connection again
        check_remote_db_connection
        check_status "Remote database connection verification"
        
        # Run a simple E2E test if available
        if [ -f "$SCRIPT_DIR/../node_modules/.bin/playwright" ]; then
            echo "Running a simple Playwright test to verify database connection..."
            cd "$SCRIPT_DIR/.." && npx playwright test -g "database connection" --headed
            check_status "Playwright test"
        else
            log_warning "Playwright not found. Skipping E2E test verification."
        fi
    else
        echo -e "${YELLOW}Skipping verification in dry-run mode.${NC}"
    fi
    
    # Summary
    echo -e "\n${YELLOW}Summary:${NC}"
    if [ "$DRY_RUN" = true ]; then
        echo "Dry run completed. No changes were made."
        echo "Run the script without --dry-run to apply the fixes."
    else
        echo "Database connection fix script completed."
        echo "If you encounter any issues, you can restore the backup files created during the fix process."
    fi
}

# Run the main function
main