#!/bin/bash
# health-check.sh - Comprehensive health check for the testing and deployment environment
# Usage: ./bin/health-check.sh [--verbose] [--fix] [--ci]

set -e

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

# Default settings
VERBOSE=false
FIX_ISSUES=false
CI_MODE=false
CURRENT_DATE=$(date +"%Y-%m-%d")

# Parse arguments
for arg in "$@"; do
  case $arg in
    --verbose)
      VERBOSE=true
      shift
      ;;
    --fix)
      FIX_ISSUES=true
      shift
      ;;
    --ci)
      CI_MODE=true
      shift
      ;;
  esac
done

echo -e "${GREEN}=== HVAC Community Events Health Check ===${NC}"
echo "Checking system health for testing and deployment..."

# 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/health
HEALTH_LOG="logs/health/health-check-${CURRENT_DATE}.log"

# Log function
log() {
  echo "[$(date +"%Y-%m-%d %H:%M:%S")] $1" >> "$HEALTH_LOG"
  if [ "$VERBOSE" = true ]; then
    echo "$1"
  else
    echo "$2"
  fi
}

# Function to check a component and report status
check_component() {
  local component=$1
  local check_command=$2
  local fix_command=$3
  
  echo -e "\n${YELLOW}Checking: ${component}${NC}"
  log "Checking component: ${component}" "Checking: ${component}..."
  
  if eval "${check_command}"; then
    echo -e "${GREEN}✓ ${component} check passed${NC}"
    log "✓ ${component} check passed" 
    return 0
  else
    echo -e "${RED}✗ ${component} check failed${NC}"
    log "✗ ${component} check failed"
    
    if [ -n "$fix_command" ] && [ "$FIX_ISSUES" = true ]; then
      echo -e "${YELLOW}Attempting to fix: ${component}${NC}"
      log "Attempting to fix: ${component}" "Attempting to fix..."
      
      if eval "${fix_command}"; then
        echo -e "${GREEN}✓ ${component} fixed successfully${NC}"
        log "✓ ${component} fixed successfully"
        return 0
      else
        echo -e "${RED}✗ Failed to fix: ${component}${NC}"
        log "✗ Failed to fix: ${component}"
        return 1
      fi
    fi
    
    return 1
  fi
}

# Function to check npm dependencies
check_npm_dependencies() {
  log "Checking npm dependencies" "Checking npm dependencies..."
  
  # Check if package.json exists
  if [ ! -f "package.json" ]; then
    log "package.json not found" "package.json not found"
    return 1
  fi
  
  # Check if node_modules exists
  if [ ! -d "node_modules" ]; then
    log "node_modules not found" "node_modules not found"
    return 1
  }
  
  # Check Playwright installation
  if ! npm list @playwright/test > /dev/null 2>&1; then
    log "Playwright not installed properly" "Playwright not installed properly"
    return 1
  fi
  
  log "npm dependencies check passed" "npm dependencies ok"
  return 0
}

# Function to fix npm dependencies
fix_npm_dependencies() {
  log "Fixing npm dependencies" "Fixing npm dependencies..."
  
  # Install dependencies
  npm install
  
  # Install Playwright browsers
  npx playwright install
  
  log "npm dependencies fixed" "npm dependencies fixed"
  return 0
}

# Function to check test configuration
check_test_config() {
  log "Checking test configuration" "Checking test configuration..."
  
  # Check if playwright.config.ts exists
  if [ ! -f "playwright.config.ts" ]; then
    log "playwright.config.ts not found" "playwright.config.ts not found"
    return 1
  fi
  
  # Check if config files exist
  if [ ! -f "tests/e2e/config/staging-config.ts" ]; then
    log "staging-config.ts not found" "staging-config.ts not found"
    return 1
  fi
  
  log "Test configuration check passed" "Test configuration ok"
  return 0
}

# Function to check test data
check_test_data() {
  log "Checking test data" "Checking test data..."
  
  # Check if test data directory exists
  if [ ! -d "tests/e2e/data" ]; then
    log "tests/e2e/data directory not found" "tests/e2e/data directory not found"
    return 1
  fi
  
  # Check if essential test data files exist
  if [ ! -f "tests/e2e/data/test-users.ts" ] || [ ! -f "tests/e2e/data/test-events.ts" ]; then
    log "Essential test data files missing" "Essential test data files missing"
    return 1
  fi
  
  log "Test data check passed" "Test data ok"
  return 0
}

# Function to fix test data
fix_test_data() {
  log "Fixing test data" "Fixing test data..."
  
  # Generate test data
  bash bin/test-data-manager.sh generate
  
  log "Test data fixed" "Test data fixed"
  return 0
}

# Function to check page objects
check_page_objects() {
  log "Checking page objects" "Checking page objects..."
  
  # Check if page object directory exists
  if [ ! -d "tests/e2e/pages" ]; then
    log "tests/e2e/pages directory not found" "tests/e2e/pages directory not found"
    return 1
  fi
  
  # Check if essential page objects exist
  if [ ! -f "tests/e2e/pages/BasePage.ts" ] || [ ! -f "tests/e2e/pages/LoginPage.ts" ]; then
    log "Essential page objects missing" "Essential page objects missing"
    return 1
  fi
  
  # Check selectors in LoginPage
  if ! grep -q "input\[name=\"log\"\]" "tests/e2e/pages/LoginPage.ts"; then
    log "LoginPage.ts missing updated selectors" "LoginPage.ts missing updated selectors"
    return 1
  fi
  
  log "Page objects check passed" "Page objects ok"
  return 0
}

# Function to fix page objects
fix_page_objects() {
  log "Fixing page objects" "Fixing page objects..."
  
  # Create required directories
  mkdir -p tests/e2e/pages
  
  # Fix LoginPage.ts with updated selectors
  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
  
  # Create BasePage.ts if missing
  if [ ! -f "tests/e2e/pages/BasePage.ts" ]; then
    cat > "tests/e2e/pages/BasePage.ts" << 'EOF'
import { Page } from '@playwright/test';
import { STAGING_URL } from '../config/staging-config';

/**
 * Base page object with common functionality for all pages
 */
export class BasePage {
  protected page: Page;
  
  constructor(page: Page) {
    this.page = page;
  }
  
  /**
   * Get the current URL
   */
  async getUrl(): Promise<string> {
    return this.page.url();
  }
  
  /**
   * Wait for page to load completely
   */
  async waitForPageLoad(): Promise<void> {
    await this.page.waitForLoadState('networkidle');
  }
  
  /**
   * Log a message with the page class name
   */
  protected log(message: string): void {
    console.log(`[${this.constructor.name}] ${message}`);
  }
  
  /**
   * Take a screenshot with a descriptive name
   */
  async takeScreenshot(name: string): Promise<void> {
    const screenshotName = `${this.constructor.name}-${name}-${Date.now()}.png`;
    await this.page.screenshot({ path: `screenshots/${screenshotName}` });
    this.log(`Screenshot saved: ${screenshotName}`);
  }
  
  /**
   * Check if an element is visible
   */
  async isElementVisible(selector: string): Promise<boolean> {
    return await this.page.isVisible(selector);
  }
}
EOF
  fi
  
  log "Page objects fixed" "Page objects fixed"
  return 0
}

# Function to check scripts
check_scripts() {
  log "Checking scripts" "Checking scripts..."
  
  # Check if bin directory exists
  if [ ! -d "bin" ]; then
    log "bin directory not found" "bin directory not found"
    return 1
  fi
  
  # Check if essential scripts exist and are executable
  local missing_scripts=0
  
  # Define essential scripts
  essential_scripts=(
    "verify-selectors.sh"
    "pre-deploy-validation.sh"
    "auto-recovery.sh"
    "test-data-manager.sh"
  )
  
  for script in "${essential_scripts[@]}"; do
    if [ ! -f "bin/$script" ] || [ ! -x "bin/$script" ]; then
      log "Essential script missing or not executable: $script" "Missing script: $script"
      missing_scripts=$((missing_scripts + 1))
    fi
  done
  
  if [ $missing_scripts -gt 0 ]; then
    log "$missing_scripts essential scripts missing" "$missing_scripts essential scripts missing"
    return 1
  fi
  
  log "Scripts check passed" "Scripts ok"
  return 0
}

# Function to check documentation
check_documentation() {
  log "Checking documentation" "Checking documentation..."
  
  # Check if essential documentation exists
  local missing_docs=0
  
  # Define essential documentation
  essential_docs=(
    "TESTING.md"
    "DEPLOYMENT-RESILIENCE.md"
    "TROUBLESHOOTING.md"
    "SELECTORS.md"
  )
  
  for doc in "${essential_docs[@]}"; do
    if [ ! -f "$doc" ]; then
      log "Essential documentation missing: $doc" "Missing doc: $doc"
      missing_docs=$((missing_docs + 1))
    fi
  done
  
  if [ $missing_docs -gt 0 ]; then
    log "$missing_docs essential documentation files missing" "$missing_docs essential docs missing"
    return 1
  fi
  
  log "Documentation check passed" "Documentation ok"
  return 0
}

# Function to check test results
check_test_results() {
  log "Checking test results" "Checking test results..."
  
  # Check if test results directory exists
  if [ ! -d "test-results" ]; then
    log "No test results found. Tests may not have been run yet." "No test results found"
    return 0  # Not a failure, tests might not have been run yet
  fi
  
  # Count recent test results
  local recent_results=$(find test-results -type f -name "*.json" -mtime -1 | wc -l)
  
  if [ $recent_results -eq 0 ]; then
    log "No recent test results found in the last 24 hours" "No recent test results"
    return 0  # Not a failure, but worth noting
  fi
  
  # Check pass rate if we have results
  local total_tests=$(find test-results -name "*.json" | wc -l)
  local passed_tests=$(grep -r '"status":"passed"' test-results | wc -l)
  
  if [ $total_tests -gt 0 ]; then
    local pass_rate=$((passed_tests * 100 / total_tests))
    
    log "Test pass rate: $pass_rate% ($passed_tests/$total_tests)" "Test pass rate: $pass_rate%"
    
    if [ $pass_rate -lt 80 ]; then
      log "Warning: Test pass rate below 80%" "Warning: Low pass rate"
      return 1
    fi
  fi
  
  log "Test results check passed" "Test results ok"
  return 0
}

# Function to check staging connectivity
check_staging_connectivity() {
  log "Checking staging connectivity" "Checking staging connectivity..."
  
  # Ping the staging server (placeholder - update with actual staging URL)
  if ping -c 1 wordpress-974670-5399585.cloudwaysapps.com &> /dev/null; then
    log "Staging server is reachable" "Staging server reachable"
  else
    log "Warning: Cannot reach staging server" "Warning: Cannot reach staging"
    return 1
  fi
  
  # Check if we can load the staging URL
  if curl -s --head https://wordpress-974670-5399585.cloudwaysapps.com/ | grep "200 OK" > /dev/null; then
    log "Staging URL returns 200 OK" "Staging URL OK"
  else
    log "Warning: Staging URL not returning 200 OK" "Warning: Staging URL not OK"
    return 1
  fi
  
  log "Staging connectivity check passed" "Staging connectivity ok"
  return 0
}

# Function to check for potential issues
check_potential_issues() {
  log "Checking for potential issues" "Checking for potential issues..."
  
  # Check for uncommitted changes
  if [ -n "$(git status --porcelain)" ]; then
    log "Warning: Uncommitted changes detected" "Warning: Uncommitted changes"
  fi
  
  # Check for large files in test results
  local large_files=$(find test-results -type f -size +10M | wc -l)
  if [ $large_files -gt 0 ]; then
    log "Warning: $large_files large files (>10MB) found in test results" "Warning: Large test result files"
  fi
  
  # Check disk space
  local disk_usage=$(df -h . | awk 'NR==2 {print $5}' | tr -d '%')
  if [ $disk_usage -gt 90 ]; then
    log "Warning: Disk usage is high ($disk_usage%)" "Warning: High disk usage"
    return 1
  fi
  
  log "Potential issues check passed" "No major issues found"
  return 0
}

# Run all checks
echo -e "\n${GREEN}=== Running Health Checks ===${NC}"

check_component "npm dependencies" check_npm_dependencies fix_npm_dependencies
NPM_STATUS=$?

check_component "test configuration" check_test_config
CONFIG_STATUS=$?

check_component "test data" check_test_data fix_test_data
DATA_STATUS=$?

check_component "page objects" check_page_objects fix_page_objects
PAGES_STATUS=$?

check_component "scripts" check_scripts
SCRIPTS_STATUS=$?

check_component "documentation" check_documentation
DOCS_STATUS=$?

check_component "test results" check_test_results
RESULTS_STATUS=$?

check_component "staging connectivity" check_staging_connectivity
STAGING_STATUS=$?

check_component "potential issues" check_potential_issues
ISSUES_STATUS=$?

# Calculate overall health score
TOTAL_CHECKS=9
PASSED_CHECKS=$((
  (NPM_STATUS == 0 ? 1 : 0) +
  (CONFIG_STATUS == 0 ? 1 : 0) +
  (DATA_STATUS == 0 ? 1 : 0) +
  (PAGES_STATUS == 0 ? 1 : 0) +
  (SCRIPTS_STATUS == 0 ? 1 : 0) +
  (DOCS_STATUS == 0 ? 1 : 0) +
  (RESULTS_STATUS == 0 ? 1 : 0) +
  (STAGING_STATUS == 0 ? 1 : 0) +
  (ISSUES_STATUS == 0 ? 1 : 0)
))

HEALTH_SCORE=$((PASSED_CHECKS * 100 / TOTAL_CHECKS))

# Summary
echo -e "\n${GREEN}=== Health Check Summary ===${NC}"
echo -e "Health Score: ${HEALTH_SCORE}% ($PASSED_CHECKS/$TOTAL_CHECKS)"

if [ $HEALTH_SCORE -eq 100 ]; then
  echo -e "${GREEN}✓ All health checks passed${NC}"
  log "All health checks passed. Health Score: 100%" "All health checks passed"
  exit 0
elif [ $HEALTH_SCORE -ge 80 ]; then
  echo -e "${YELLOW}⚠ Some minor issues detected${NC}"
  log "Some minor issues detected. Health Score: $HEALTH_SCORE%" "Some minor issues detected"
  
  if [ "$CI_MODE" = true ]; then
    echo -e "CI mode enabled, but passing due to acceptable health score"
    exit 0
  fi
  
  exit 0
else
  echo -e "${RED}✗ Significant issues detected${NC}"
  log "Significant issues detected. Health Score: $HEALTH_SCORE%" "Significant issues detected"
  
  if [ "$CI_MODE" = true ]; then
    echo -e "CI mode enabled, failing build due to low health score"
    exit 1
  fi
  
  exit 1
fi