#!/bin/bash
# auto-recovery.sh - Script to automatically recover from common test failures
# Usage: ./bin/auto-recovery.sh [--ci] [--force]

set -e

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

# Parse arguments
CI_MODE=false
FORCE_MODE=false

for arg in "$@"; do
  case $arg in
    --ci)
      CI_MODE=true
      shift
      ;;
    --force)
      FORCE_MODE=true
      shift
      ;;
  esac
done

echo -e "${GREEN}=== Automated Recovery Tool ===${NC}"
echo "Attempting to recover from common test failures..."

# Check if we're in the right directory
if [ ! -d "tests/e2e" ]; then
  echo -e "${RED}Error: Please run this script from the wordpress-dev directory${NC}"
  exit 1
fi

# Create logs directory
mkdir -p logs/recovery

# Log function
log() {
  echo "[$(date +"%Y-%m-%d %H:%M:%S")] $1" >> logs/recovery/recovery-$(date +"%Y%m%d").log
  echo "$1"
}

# Function to check if a command exists
command_exists() {
  command -v "$1" >/dev/null 2>&1
}

# Function to run a recovery action
run_recovery() {
  local action_name=$1
  local action_command=$2
  
  log "Running recovery action: ${action_name}"
  
  if eval "${action_command}"; then
    log "${GREEN}✓ Recovery successful: ${action_name}${NC}"
    return 0
  else
    log "${RED}✗ Recovery failed: ${action_name}${NC}"
    return 1
  fi
}

# Check the test results to determine what failed
check_test_failures() {
  log "Analyzing test failures..."
  
  # Check for login failures
  if grep -q "LoginPage" test-results/*.txt 2>/dev/null || \
     grep -q "Error: locator.fill: Test timeout" test-results/*.txt 2>/dev/null; then
    log "${YELLOW}Detected login page failures${NC}"
    RECOVERY_ACTIONS+=(fix_login_selectors)
    RECOVERY_ACTIONS+=(reset_test_users)
  fi
  
  # Check for certificate failures
  if grep -q "CertificatePage" test-results/*.txt 2>/dev/null || \
     grep -q "certificate" test-results/*.txt 2>/dev/null; then
    log "${YELLOW}Detected certificate system failures${NC}"
    RECOVERY_ACTIONS+=(fix_certificate_system)
    RECOVERY_ACTIONS+=(regenerate_certificate_data)
  fi
  
  # Check for plugin activation failures
  if grep -q "plugin" test-results/*.txt 2>/dev/null || \
     grep -q "activation" test-results/*.txt 2>/dev/null; then
    log "${YELLOW}Detected plugin activation failures${NC}"
    RECOVERY_ACTIONS+=(reset_plugin)
  fi
  
  # Check for dashboard failures
  if grep -q "DashboardPage" test-results/*.txt 2>/dev/null || \
     grep -q "dashboard" test-results/*.txt 2>/dev/null; then
    log "${YELLOW}Detected dashboard failures${NC}"
    RECOVERY_ACTIONS+=(reset_events)
  fi
  
  # If no specific failures detected or force mode, run all recovery actions
  if [ ${#RECOVERY_ACTIONS[@]} -eq 0 ] || [ "$FORCE_MODE" = true ]; then
    log "${YELLOW}Running all recovery actions (force mode or general failure)${NC}"
    RECOVERY_ACTIONS=(fix_login_selectors reset_test_users fix_certificate_system regenerate_certificate_data reset_plugin reset_events)
  fi
}

# Recovery actions
fix_login_selectors() {
  log "Fixing login selectors..."
  
  # Run login debug script
  npx playwright test tests/e2e/debug-login-page.spec.ts --config=playwright.config.ts || true
  
  # Create backup of LoginPage.ts
  cp tests/e2e/pages/LoginPage.ts tests/e2e/pages/LoginPage.ts.bak
  
  # Update selectors based on debug output
  cat > tests/e2e/pages/LoginPage.ts << 'EOF'
import { Page, expect } from '@playwright/test';
import { BasePage } from './BasePage';
import { PATHS } from '../config/staging-config';

/**
 * Page object representing the login page
 */
export class LoginPage extends BasePage {
  // Login form elements based on debug analysis
  private readonly usernameInput = 'input[name="log"]';
  private readonly passwordInput = 'input[name="pwd"]';
  private readonly loginButton = 'input[type="submit"]';
  private readonly rememberMeCheckbox = 'input[name="rememberme"]';
  private readonly loginError = '.login-error, .login_error, #login_error, .notice-error, .woocommerce-error, .wp-die-message';
  private readonly forgotPasswordLink = 'a:text("Lost your password?")';
  private readonly loginForm = 'form#hvac_community_loginform';

  constructor(page: Page) {
    super(page);
  }

  /**
   * Navigate to the login page
   */
  async navigate(): Promise<void> {
    this.log('Navigating to login page');
    await this.page.goto(PATHS.login);
    await this.page.waitForLoadState('networkidle');
    
    // Make sure the form is visible before proceeding
    await this.page.waitForSelector(this.loginForm, { timeout: 10000 });
  }
  
  /**
   * Alternative name for navigate for backward compatibility
   */
  async navigateToLogin(): Promise<void> {
    await this.navigate();
  }

  /**
   * Login with provided credentials
   * @param username Username or email
   * @param password Password
   */
  async login(username: string, password: string): Promise<void> {
    this.log(`Logging in as ${username}`);
    
    // Wait for form elements to be ready
    await this.page.waitForSelector(this.usernameInput, { state: 'visible', timeout: 10000 });
    await this.page.waitForSelector(this.passwordInput, { state: 'visible', timeout: 5000 });
    await this.page.waitForSelector(this.loginButton, { state: 'visible', timeout: 5000 });
    
    // Fill in the credentials
    await this.page.fill(this.usernameInput, username);
    await this.page.fill(this.passwordInput, password);
    
    // Click login and wait for navigation
    await this.page.click(this.loginButton);
    await this.page.waitForLoadState('networkidle');
    
    this.log('Login form submitted');
  }

  /**
   * Check if we're logged in
   */
  async isLoggedIn(): Promise<boolean> {
    await this.page.waitForLoadState('networkidle');
    const url = await this.getUrl();
    return url.includes('hvac-dashboard');
  }

  /**
   * Check if username field is visible
   */
  async isUsernameFieldVisible(): Promise<boolean> {
    try {
      await this.page.waitForSelector(this.usernameInput, { state: 'visible', timeout: 5000 });
      return true;
    } catch (error) {
      return false;
    }
  }

  /**
   * Get error message if login failed
   */
  async getErrorMessage(): Promise<string | null> {
    // Check all possible error selectors
    const errorSelectors = this.loginError.split(', ');
    
    for (const selector of errorSelectors) {
      if (await this.page.isVisible(selector)) {
        return await this.page.textContent(selector);
      }
    }
    
    // Check for any text containing common error messages
    const pageContent = await this.page.content();
    if (pageContent.includes('Invalid username') || 
        pageContent.includes('incorrect password') ||
        pageContent.includes('Unknown username') ||
        pageContent.includes('Error:')) {
      
      // Try to find error message in the page content
      const errorText = await this.page.evaluate(() => {
        const errorElements = Array.from(document.querySelectorAll('p, div, span'))
          .filter(el => el.textContent && 
            (el.textContent.includes('Invalid') || 
             el.textContent.includes('Error') || 
             el.textContent.includes('incorrect') ||
             el.textContent.includes('Unknown')));
        
        return errorElements.length > 0 ? errorElements[0].textContent : null;
      });
      
      return errorText;
    }
    
    return null;
  }

  /**
   * Click on "forgot password" link
   */
  async clickForgotPassword(): Promise<void> {
    await this.page.click(this.forgotPasswordLink);
    await this.page.waitForLoadState('networkidle');
  }

  /**
   * Toggle "remember me" checkbox
   * @param check If true, check the box; if false, uncheck it
   */
  async setRememberMe(check: boolean): Promise<void> {
    const isChecked = await this.page.isChecked(this.rememberMeCheckbox);
    if (check !== isChecked) {
      await this.page.click(this.rememberMeCheckbox);
    }
  }
}
EOF

  log "${GREEN}Updated LoginPage.ts with robust selectors${NC}"
  return 0
}

reset_test_users() {
  log "Resetting test users..."
  
  if [ -f "bin/create-test-users.sh" ]; then
    bash bin/create-test-users.sh
    return $?
  else
    log "${YELLOW}create-test-users.sh not found, creating default test users${NC}"
    
    # Create a basic script to create test users
    cat > bin/create-test-users.sh << 'EOF'
#!/bin/bash
# Create test users for E2E testing

# Create test_trainer user
ssh user@staging-server "cd /path/to/wordpress && wp user create test_trainer test_trainer@example.com --role=subscriber --user_pass=Test123! || wp user update test_trainer --role=subscriber --user_pass=Test123!"

# Create admin_trainer user
ssh user@staging-server "cd /path/to/wordpress && wp user create admin_trainer admin_trainer@example.com --role=administrator --user_pass=Admin123! || wp user update admin_trainer --role=administrator --user_pass=Admin123!"

echo "Test users created/updated successfully"
EOF
    
    chmod +x bin/create-test-users.sh
    log "${YELLOW}Created create-test-users.sh script, please update SSH credentials before using${NC}"
    return 1
  fi
}

fix_certificate_system() {
  log "Fixing certificate system..."
  
  if [ -f "bin/fix-certificate-system.sh" ]; then
    bash bin/fix-certificate-system.sh
    return $?
  else
    log "${YELLOW}fix-certificate-system.sh not found, skipping${NC}"
    return 1
  fi
}

regenerate_certificate_data() {
  log "Regenerating certificate test data..."
  
  if [ -f "bin/create-test-data-with-checkins.sh" ]; then
    bash bin/create-test-data-with-checkins.sh
    return $?
  else
    log "${YELLOW}create-test-data-with-checkins.sh not found, skipping${NC}"
    return 1
  fi
}

reset_plugin() {
  log "Resetting plugin state..."
  
  if [ -f "bin/reset-plugin-state.sh" ]; then
    bash bin/reset-plugin-state.sh
    return $?
  else
    log "${YELLOW}reset-plugin-state.sh not found, creating default script${NC}"
    
    # Create a basic script to reset plugin state
    cat > bin/reset-plugin-state.sh << 'EOF'
#!/bin/bash
# Reset plugin state by deactivating and reactivating

# Deactivate plugin
ssh user@staging-server "cd /path/to/wordpress && wp plugin deactivate hvac-community-events"

# Wait a moment
sleep 2

# Reactivate plugin
ssh user@staging-server "cd /path/to/wordpress && wp plugin activate hvac-community-events"

echo "Plugin reset successfully"
EOF
    
    chmod +x bin/reset-plugin-state.sh
    log "${YELLOW}Created reset-plugin-state.sh script, please update SSH credentials before using${NC}"
    return 1
  fi
}

reset_events() {
  log "Resetting test events..."
  
  if [ -f "bin/create-test-events-admin.sh" ]; then
    bash bin/create-test-events-admin.sh
    return $?
  else
    log "${YELLOW}create-test-events-admin.sh not found, skipping${NC}"
    return 1
  fi
}

# Main recovery logic
RECOVERY_ACTIONS=()
SUCCESSES=0
FAILURES=0

# Check for test failures
check_test_failures

# Run recovery actions
log "Running ${#RECOVERY_ACTIONS[@]} recovery actions..."

for action in "${RECOVERY_ACTIONS[@]}"; do
  if run_recovery "$action" "$action"; then
    SUCCESSES=$((SUCCESSES + 1))
  else
    FAILURES=$((FAILURES + 1))
  fi
done

# Summary
log "\n${GREEN}=== Recovery Summary ===${NC}"
if [ $FAILURES -eq 0 ]; then
  log "${GREEN}✓ All recovery actions completed successfully${NC}"
  log "Total: ${#RECOVERY_ACTIONS[@]}, Succeeded: ${SUCCESSES}, Failed: ${FAILURES}"
  exit 0
else
  log "${YELLOW}⚠ Some recovery actions failed${NC}"
  log "Total: ${#RECOVERY_ACTIONS[@]}, Succeeded: ${SUCCESSES}, Failed: ${FAILURES}"
  
  if [ "$CI_MODE" = true ]; then
    log "${RED}CI mode enabled, failing build due to recovery failures${NC}"
    exit 1
  fi
  
  log "Please check the logs and try manual recovery for failed actions"
  exit 1
fi