#!/bin/bash

# Velero Backup Hook Count Verification Script
# Creates backup with hooks and verifies that Backup Item Operations 
# Attempted/Completed correctly reflect the total number of hooks 
# executed across all pods

set -e

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

# Default values
BACKUP_NAME=""
APP_NAMESPACE=""
VELERO_NAMESPACE="openshift-adp"
EXPECTED_PODS=2
EXPECTED_PRE_HOOKS=2  # 1 successful + 1 failed
EXPECTED_POST_HOOKS=2 # 1 successful + 1 failed
EXPECTED_PRE_HOOK_FAILURES=1  # 1 failed pre-hook per pod
EXPECTED_POST_HOOK_FAILURES=1 # 1 failed post-hook per pod
CREATE_BACKUP=false
WAIT_COMPLETION=true
VERBOSE=false

usage() {
    cat << EOF
Usage: $0 -b <backup-name> -a <app-namespace> [options]

Options:
    -b, --backup <name>      Name for the Velero backup (required)
    -a, --app-namespace <ns> Namespace containing the app to backup (required)
    -n, --namespace <ns>     Velero namespace (default: openshift-adp)
    -p, --pods <count>       Expected number of pods (default: 2)
    --pre-hooks <count>      Expected number of pre hooks per pod (default: 2)
    --post-hooks <count>     Expected number of post hooks per pod (default: 2)
    -c, --create             Create the backup (if not specified, only verify existing)
    --no-wait               Don't wait for backup completion
    -v, --verbose           Enable verbose output
    -h, --help              Show this help message

Example:
    # Create backup and verify
    $0 -b mysql-hooks-backup -a test-app -c

    # Only verify existing backup
    $0 -b mysql-hooks-backup -a test-app
EOF
}

log() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1"
}

# Parse command line arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        -b|--backup)
            BACKUP_NAME="$2"
            shift 2
            ;;
        -a|--app-namespace)
            APP_NAMESPACE="$2"
            shift 2
            ;;
        -n|--namespace)
            VELERO_NAMESPACE="$2"
            shift 2
            ;;
        -p|--pods)
            EXPECTED_PODS="$2"
            shift 2
            ;;
        --pre-hooks)
            EXPECTED_PRE_HOOKS="$2"
            shift 2
            ;;
        --post-hooks)
            EXPECTED_POST_HOOKS="$2"
            shift 2
            ;;
        -c|--create)
            CREATE_BACKUP=true
            shift
            ;;
        --no-wait)
            WAIT_COMPLETION=false
            shift
            ;;
        -v|--verbose)
            VERBOSE=true
            shift
            ;;
        -h|--help)
            usage
            exit 0
            ;;
        *)
            error "Unknown option: $1"
            usage
            exit 1
            ;;
    esac
done

# Validate required parameters
if [[ -z "$BACKUP_NAME" ]]; then
    error "Backup name is required. Use -b or --backup option."
    usage
    exit 1
fi

if [[ -z "$APP_NAMESPACE" ]]; then
    error "App namespace is required. Use -a or --app-namespace option."
    usage
    exit 1
fi

# Check if kubectl/oc is available
if command -v oc &> /dev/null; then
    KUBECTL_CMD="oc"
elif command -v kubectl &> /dev/null; then
    KUBECTL_CMD="kubectl"
else
    error "Neither 'oc' nor 'kubectl' command found. Please install one of them."
    exit 1
fi

# Check if velero CLI is available
if ! command -v velero &> /dev/null; then
    error "Velero CLI not found. Please install velero CLI."
    exit 1
fi

log "Using kubectl command: $KUBECTL_CMD"
log "Backup name: $BACKUP_NAME"
log "App namespace: $APP_NAMESPACE"
log "Velero namespace: $VELERO_NAMESPACE"

# Verify app namespace exists and has expected pods
if ! $KUBECTL_CMD get namespace "$APP_NAMESPACE" &> /dev/null; then
    error "App namespace '$APP_NAMESPACE' not found"
    exit 1
fi

ACTUAL_PODS=$($KUBECTL_CMD get pods -n "$APP_NAMESPACE" --no-headers | wc -l)
log "Found $ACTUAL_PODS pods in namespace $APP_NAMESPACE"

if [[ "$ACTUAL_PODS" -ne "$EXPECTED_PODS" ]]; then
    warn "Expected $EXPECTED_PODS pods, found $ACTUAL_PODS"
fi

create_backup() {
    log "Creating Velero backup with hooks..."
    
    # Create backup with hooks using the correct API specification
    log "Creating backup with hooks using proper API spec..."
    
    cat > /tmp/backup-with-hooks.yaml << EOF
apiVersion: velero.io/v1
kind: Backup
metadata:
  name: $BACKUP_NAME
  namespace: $VELERO_NAMESPACE
spec:
  includedNamespaces:
  - $APP_NAMESPACE
  hooks:
    resources:
    - name: backup-hook-test
      includedNamespaces:
      - $APP_NAMESPACE
      includedResources:
      - pods
      pre:
      - exec:
          command: ["/bin/sh", "-c", "echo 'Pre-hook 1: SUCCESSFUL at \$(date)' && exit 0"]
          onError: Continue
          timeout: 30s
      - exec:
          command: ["/bin/sh", "-c", "echo 'Pre-hook 2: FAILED at \$(date)' && exit 1"]
          onError: Continue
          timeout: 30s
      post:
      - exec:
          command: ["/bin/sh", "-c", "echo 'Post-hook 1: SUCCESSFUL at \$(date)' && exit 0"]
          onError: Continue
          timeout: 30s
      - exec:
          command: ["/bin/sh", "-c", "echo 'Post-hook 2: FAILED at \$(date)' && exit 1"]
          onError: Continue
          timeout: 30s
  excludedResources:
  - nodes
  - events
  - events.events.k8s.io
  - backups.velero.io
  - restores.velero.io
  - resticrepositories.velero.io
  - csinodes.storage.k8s.io
  - volumeattachments.storage.k8s.io
  - backuprepositories.velero.io
  itemOperationTimeout: 4h0m0s
EOF
    
    # Apply the backup resource with hooks
    if $KUBECTL_CMD apply -f /tmp/backup-with-hooks.yaml; then
        success "Backup '$BACKUP_NAME' created with hooks"
        
        # Wait for backup completion if requested
        if [[ "$WAIT_COMPLETION" == true ]]; then
            log "Waiting for backup to complete..."
            # Wait up to 10 minutes for completion
            for i in {1..60}; do
                PHASE=$(velero backup get --namespace="$VELERO_NAMESPACE" | grep "$BACKUP_NAME" | awk '{print $3}' | head -1)
                if [[ "$PHASE" == "Completed" || "$PHASE" == "Failed" || "$PHASE" == "PartiallyFailed" ]]; then
                    break
                fi
                log "Backup phase: $PHASE - waiting... ($i/60)"
                sleep 10
            done
        fi
    else
        warn "Failed to create backup with hooks, trying velero CLI fallback..."
        # Fallback to simple velero command
        velero backup create "$BACKUP_NAME" \
            --namespace="$VELERO_NAMESPACE" \
            --include-namespaces="$APP_NAMESPACE" \
            --wait="$WAIT_COMPLETION"
    fi
    
    if [[ $? -eq 0 ]]; then
        success "Backup '$BACKUP_NAME' created successfully"
    else
        error "Failed to create backup '$BACKUP_NAME'"
        return 1
    fi
    
    # Clean up temp files
    rm -f /tmp/backup-hooks.yaml /tmp/backup-with-hooks.yaml
}

verify_backup() {
    log "Verifying backup: $BACKUP_NAME"
    
    # Check if backup exists
    if ! velero backup describe "$BACKUP_NAME" --namespace="$VELERO_NAMESPACE" &> /dev/null; then
        error "Backup '$BACKUP_NAME' not found"
        return 1
    fi
    
    # Get backup details using both velero CLI and kubectl
    BACKUP_YAML=$($KUBECTL_CMD get backups.velero.io "$BACKUP_NAME" -n "$VELERO_NAMESPACE" -o yaml 2>/dev/null)
    BACKUP_DESCRIBE=$(velero backup describe "$BACKUP_NAME" --namespace="$VELERO_NAMESPACE" --details 2>/dev/null)
    
    if [[ $VERBOSE == true ]]; then
        log "Backup YAML:"
        echo "$BACKUP_YAML"
        echo ""
        log "Velero describe output:"
        echo "$BACKUP_DESCRIBE"
        echo ""
    fi
    
    # Extract hook information from spec
    PRE_HOOKS_COUNT=$(echo "$BACKUP_YAML" | grep -c "preHooks:" 2>/dev/null || echo "0")
    POST_HOOKS_COUNT=$(echo "$BACKUP_YAML" | grep -c "postHooks:" 2>/dev/null || echo "0")
    
    # Alternative parsing if grep doesn't work well
    if [[ "$PRE_HOOKS_COUNT" -eq 0 && "$POST_HOOKS_COUNT" -eq 0 ]]; then
        # Try counting exec commands in hooks section
        PRE_HOOKS_COUNT=$(echo "$BACKUP_YAML" | grep -A 50 "preHooks:" | grep -c "exec:" || echo "0")
        POST_HOOKS_COUNT=$(echo "$BACKUP_YAML" | grep -A 50 "postHooks:" | grep -c "exec:" || echo "0")
    fi
    
    # Extract status information
    PHASE=$(echo "$BACKUP_YAML" | grep "phase:" | awk '{print $2}' | tail -1 || echo "Unknown")
    HOOKS_ATTEMPTED=$(echo "$BACKUP_YAML" | grep "hooksAttempted:" | awk '{print $2}' || echo "0")
    HOOKS_FAILED=$(echo "$BACKUP_YAML" | grep "hooksFailed:" | awk '{print $2}' || echo "0")
    BACKUP_OPS_ATTEMPTED=$(echo "$BACKUP_YAML" | grep "hooksAttempted:" | awk '{print $2}' || echo "0")  
    BACKUP_OPS_COMPLETED=$HOOKS_ATTEMPTED  # Use hooksAttempted as completed count
    
    # Also try to get from velero describe output
    if [[ "$BACKUP_OPS_ATTEMPTED" == "0" ]]; then
        BACKUP_OPS_ATTEMPTED=$(echo "$BACKUP_DESCRIBE" | grep -i "backup item operations attempted" | awk '{print $NF}' || echo "0")
        BACKUP_OPS_COMPLETED=$(echo "$BACKUP_DESCRIBE" | grep -i "backup item operations completed" | awk '{print $NF}' || echo "0")
    fi
    
    # Calculate expected values
    EXPECTED_TOTAL_HOOKS=$((EXPECTED_PRE_HOOKS + EXPECTED_POST_HOOKS))
    EXPECTED_TOTAL_OPERATIONS=$((EXPECTED_TOTAL_HOOKS * ACTUAL_PODS))
    EXPECTED_TOTAL_FAILURES=$(((EXPECTED_PRE_HOOK_FAILURES + EXPECTED_POST_HOOK_FAILURES) * ACTUAL_PODS))
    
    log "=== Hook Configuration ==="
    log "Pre hooks per pod: $PRE_HOOKS_COUNT"
    log "Post hooks per pod: $POST_HOOKS_COUNT"
    log "Actual pods: $ACTUAL_PODS"
    log "Expected total hooks per pod: $EXPECTED_TOTAL_HOOKS"
    log "Expected total operations: $EXPECTED_TOTAL_OPERATIONS"
    
    log ""
    log "=== Backup Status ==="
    log "Phase: $PHASE"
    log "Hooks Attempted: $HOOKS_ATTEMPTED"
    log "Hooks Failed: $HOOKS_FAILED"
    
    log ""
    log "=== Verification Results ==="
    
    ISSUES_FOUND=0
    
    # Verify the main bug: hooks should equal (hooks per pod) * (number of pods)
    if [[ "$HOOKS_ATTEMPTED" -ne "$EXPECTED_TOTAL_OPERATIONS" ]]; then
        error "BUG CONFIRMED: Hooks Attempted is $HOOKS_ATTEMPTED, expected $EXPECTED_TOTAL_OPERATIONS"
        error "This indicates the bug where hooks are counted as 1 per pod instead of (hooks per pod) * (number of pods)"
        ((ISSUES_FOUND++))
    else
        success "Hooks Attempted count is correct: $HOOKS_ATTEMPTED"
    fi
    
    # Verify hook failures are counted correctly
    if [[ "$HOOKS_FAILED" -ne "$EXPECTED_TOTAL_FAILURES" ]]; then
        error "Hook Failures count is $HOOKS_FAILED, expected $EXPECTED_TOTAL_FAILURES"
        ((ISSUES_FOUND++))
    else
        success "Hook Failures count is correct: $HOOKS_FAILED"
    fi
    
    # Summary
    log ""
    log "=== Summary ==="
    if [[ $ISSUES_FOUND -eq 0 ]]; then
        success "All hook operation counts are correct!"
        return 0
    else
        error "Found $ISSUES_FOUND issue(s) with hook operation counting"
        
        log ""
        log "=== Expected Behavior (Velero 1.13+ fix) ==="
        log "- Each exec hook in each pod should be counted separately"
        log "- With $ACTUAL_PODS pods and $EXPECTED_TOTAL_HOOKS hooks per pod:"
        log "  * Backup Item Operations Attempted should be: $EXPECTED_TOTAL_OPERATIONS"
        log "  * Backup Item Operations Completed should be: $EXPECTED_TOTAL_OPERATIONS"
        log ""
        log "=== Current (Buggy) Behavior ==="
        log "- Only 1 operation counted per pod regardless of number of hooks"
        log "- This results in lower counts than expected"
        
        return 1
    fi
}

# Main execution
if [[ "$CREATE_BACKUP" == true ]]; then
    create_backup
    if [[ $? -ne 0 ]]; then
        exit 1
    fi
    
    if [[ "$WAIT_COMPLETION" == true ]]; then
        log "Waiting for backup to complete..."
        sleep 10  # Give some time for status to update
    fi
fi

verify_backup
exit $?
