#!/bin/bash

# GitLab Chaos Engineering Script
# Randomly introduces realistic GitLab issues for troubleshooting practice
# 
# Usage: ./gitlab-chaos.sh [--scenario=TYPE] [--severity=LEVEL] [--dry-run]
# 
# Author: Claude. GPT did prett well in it's attempts, 
# Gemini told me to do it myself. Fair, but not today.

# updated the script, everything stays the same except 
# "corrupted" values will still be valid
# so that the script can run "gitlab-ctl reconfigure".


set -euo pipefail

# Configuration
GITLAB_HOME="/var/opt/gitlab"
GITLAB_CONFIG="/etc/gitlab/gitlab.rb"
RUNNER_CONFIG="/etc/gitlab-runner/config.toml"
BACKUP_DIR="/opt/gitlab-chaos-backups"
SCENARIO_LOG="/var/log/gitlab-chaos.log"

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color

# Wrapper functions for mystery mode
mystery_log() {
    if [[ "$ORIGINAL_ARGS" == *"--scenario="* ]]; then
        log "$1"
    fi
}

mystery_success() {
    if [[ "$ORIGINAL_ARGS" == *"--scenario="* ]]; then
        success "$1"
    fi
}

# Logging function
log() {
    echo -e "${BLUE}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1" | tee -a "$SCENARIO_LOG"
}

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

warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1" | tee -a "$SCENARIO_LOG"
}

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

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

# Create backup directory if it doesn't exist
setup_backup_dir() {
    mkdir -p "$BACKUP_DIR"
    log "Backup directory: $BACKUP_DIR"
}

# Parse command line arguments
parse_args() {
    SCENARIO=""
    SEVERITY="random"
    DRY_RUN=false
    SCENARIO_SPECIFIED=false
    
    for arg in "$@"; do
        case $arg in
            --scenario=*)
                SCENARIO="${arg#*=}"
                SCENARIO_SPECIFIED=true
                ;;
            --severity=*)
                SEVERITY="${arg#*=}"
                ;;
            --dry-run)
                DRY_RUN=true
                ;;
            --help|-h)
                show_help
                exit 0
                ;;
        esac
    done
}

show_help() {
    cat << EOF
GitLab Chaos Engineering Script

Usage: $0 [OPTIONS]

OPTIONS:
    --scenario=TYPE     Specify scenario type (runner, database, storage, network, performance, config)
    --severity=LEVEL    Specify severity (low, medium, high, random)
    --dry-run          Show what would be done without executing
    --help, -h         Show this help message

SCENARIO TYPES:
    runner      - GitLab Runner authentication and configuration issues
    database    - PostgreSQL and Redis related problems
    storage     - Repository storage and filesystem issues
    network     - Network connectivity and service binding problems
    performance - Resource exhaustion and performance degradation
    config      - Configuration file corruption and service issues
    random      - Randomly select from all scenario types

SEVERITY LEVELS:
    low         - Minor issues, service remains functional
    medium      - Moderate issues, some features affected
    high        - Major issues, significant service disruption
    random      - Randomly select severity level

EXAMPLES:
    $0                              # Random scenario, random severity
    $0 --scenario=runner --severity=high
    $0 --scenario=database --dry-run
    $0 --scenario=random --severity=medium

RECOVERY:
    To restore from backups: $0 --restore
    To list active scenarios: $0 --status
EOF
}

# Backup critical files before corruption
create_backups() {
    local timestamp=$(date +%Y%m%d_%H%M%S)
    local backup_path="$BACKUP_DIR/backup_$timestamp"
    
    log "Creating backup at $backup_path"
    mkdir -p "$backup_path"
    
    # Backup runner config
    if [[ -f "$RUNNER_CONFIG" ]]; then
        cp "$RUNNER_CONFIG" "$backup_path/config.toml.backup"
    fi
    
    # Backup GitLab config
    if [[ -f "$GITLAB_CONFIG" ]]; then
        cp "$GITLAB_CONFIG" "$backup_path/gitlab.rb.backup"
    fi
    
    # Backup GitLab secrets
    if [[ -f "$GITLAB_HOME/gitlab-secrets.json" ]]; then
        cp "$GITLAB_HOME/gitlab-secrets.json" "$backup_path/gitlab-secrets.json.backup"
    fi
    
    # Store database state
    if command -v gitlab-rails >/dev/null 2>&1; then
        timeout 30 gitlab-rails runner "
            puts 'Active runners: ' + Ci::Runner.count.to_s
            puts 'Pending jobs: ' + Ci::Build.where(status: 'pending').count.to_s
            puts 'Projects: ' + Project.count.to_s
        " > "$backup_path/db_state.txt" 2>/dev/null || true
    fi
    
    echo "$backup_path" > "$BACKUP_DIR/latest_backup"
    success "Backup created: $backup_path"
}

# Generate random corruption based on scenario type and severity
generate_corruption() {
    local scenario_type="$1"
    local severity="$2"
    
    case "$scenario_type" in
        "runner")
            corrupt_runner_scenario "$severity"
            ;;
        "database")
            corrupt_database_scenario "$severity"
            ;;
        "storage")
            corrupt_storage_scenario "$severity"
            ;;
        "network")
            corrupt_network_scenario "$severity"
            ;;
        "performance")
            corrupt_performance_scenario "$severity"
            ;;
        "config")
            corrupt_config_scenario "$severity"
            ;;
        *)
            error "Unknown scenario type: $scenario_type"
            exit 1
            ;;
    esac
}

# Runner-related corruptions
corrupt_runner_scenario() {
    local severity="$1"
    local corruptions=()
    
    case "$severity" in
        "low")
            corruptions=("corrupt_runner_token" "disable_runner_service_temp")
            ;;
        "medium")
            corruptions=("corrupt_runner_token" "corrupt_runner_config" "wrong_runner_url")
            ;;
        "high")
            corruptions=("corrupt_runner_token" "corrupt_runner_config" "delete_runner_binary" "corrupt_runner_db_entry")
            ;;
    esac
    
    execute_random_corruption "${corruptions[@]}"
}

# Database-related corruptions
corrupt_database_scenario() {
    local severity="$1"
    local corruptions=()
    
    case "$severity" in
        "low")
            corruptions=("corrupt_redis_config" "temp_db_connection_issue")
            ;;
        "medium")
            corruptions=("corrupt_db_password" "corrupt_redis_config" "fill_temp_space")
            ;;
        "high")
            corruptions=("corrupt_db_password" "corrupt_postgres_config" "corrupt_db_permissions" "simulate_db_lock")
            ;;
    esac
    
    execute_random_corruption "${corruptions[@]}"
}

# Storage-related corruptions
corrupt_storage_scenario() {
    local severity="$1"
    local corruptions=()
    
    case "$severity" in
        "low")
            corruptions=("corrupt_single_repo" "wrong_storage_permissions")
            ;;
        "medium")
            corruptions=("corrupt_gitaly_config" "corrupt_multiple_repos" "fill_storage_space")
            ;;
        "high")
            corruptions=("corrupt_gitaly_config" "corrupt_storage_config" "corrupt_git_storage_path")
            ;;
    esac
    
    execute_random_corruption "${corruptions[@]}"
}

# Network-related corruptions
corrupt_network_scenario() {
    local severity="$1"
    local corruptions=()
    
    case "$severity" in
        "low")
            corruptions=("wrong_external_url" "corrupt_nginx_listen_port")
            ;;
        "medium")
            corruptions=("corrupt_nginx_config" "wrong_external_url" "block_internal_api")
            ;;
        "high")
            corruptions=("corrupt_nginx_config" "corrupt_ssl_config" "wrong_bind_address")
            ;;
    esac
    
    execute_random_corruption "${corruptions[@]}"
}

# Performance-related corruptions
corrupt_performance_scenario() {
    local severity="$1"
    local corruptions=()
    
    case "$severity" in
        "low")
            corruptions=("reduce_worker_processes" "limit_db_connections")
            ;;
        "medium")
            corruptions=("consume_memory" "reduce_worker_processes" "slow_disk_io")
            ;;
        "high")
            corruptions=("consume_memory" "consume_cpu" "fill_logs_partition")
            ;;
    esac
    
    execute_random_corruption "${corruptions[@]}"
}

# Configuration-related corruptions
corrupt_config_scenario() {
    local severity="$1"
    local corruptions=()
    
    case "$severity" in
        "low")
            corruptions=("corrupt_worker_settings" "wrong_timezone_config" "corrupt_memory_settings")
            ;;
        "medium")
            corruptions=("corrupt_gitlab_secrets" "corrupt_gitlab_yml_syntax" "wrong_service_config" "corrupt_gitaly_socket")
            ;;
        "high")
            corruptions=("corrupt_gitlab_secrets" "corrupt_main_config" "corrupt_service_files" "corrupt_ssl_redirect")
            ;;
    esac
    
    execute_random_corruption "${corruptions[@]}"
}

# Execute a random corruption from the provided list
execute_random_corruption() {
    local corruptions=("$@")
    local selected_corruption=${corruptions[$RANDOM % ${#corruptions[@]}]}
    
    # Only log corruption details if scenario was explicitly specified
    if [[ "$SCENARIO_SPECIFIED" == true ]]; then
        log "Executing corruption: $selected_corruption"
    fi
    
    if [[ "$DRY_RUN" == true ]]; then
        if [[ "$SCENARIO_SPECIFIED" == true ]]; then
            warning "DRY RUN: Would execute $selected_corruption"
        else
            warning "DRY RUN: Would execute mystery corruption"
        fi
        return
    fi
    
    # Temporarily redirect output in mystery mode
    if [[ "$SCENARIO_SPECIFIED" != true ]]; then
        exec 3>&1 4>&2  # Save current stdout/stderr
        exec 1>/dev/null 2>/dev/null  # Redirect to null
    fi
    
    case "$selected_corruption" in
        "corrupt_runner_token")
            corrupt_runner_token
            ;;
        "corrupt_runner_config")
            corrupt_runner_config
            ;;
        "disable_runner_service_temp")
            disable_runner_service_temp
            ;;
        "wrong_runner_url")
            wrong_runner_url
            ;;
        "delete_runner_binary")
            delete_runner_binary
            ;;
        "corrupt_runner_db_entry")
            corrupt_runner_db_entry
            ;;
        "corrupt_redis_config")
            corrupt_redis_config
            ;;
        "temp_db_connection_issue")
            temp_db_connection_issue
            ;;
        "corrupt_db_password")
            corrupt_db_password
            ;;
        "corrupt_postgres_config")
            corrupt_postgres_config
            ;;
        "corrupt_db_permissions")
            corrupt_db_permissions
            ;;
        "simulate_db_lock")
            simulate_db_lock
            ;;
        "corrupt_single_repo")
            corrupt_single_repo
            ;;
        "wrong_storage_permissions")
            wrong_storage_permissions
            ;;
        "corrupt_gitaly_config")
            corrupt_gitaly_config
            ;;
        "corrupt_multiple_repos")
            corrupt_multiple_repos
            ;;
        "fill_storage_space")
            fill_storage_space
            ;;
        "corrupt_storage_config")
            corrupt_storage_config
            ;;
        "corrupt_git_storage_path")
            corrupt_git_storage_path
            ;;
        "wrong_external_url")
            wrong_external_url
            ;;
        "corrupt_nginx_listen_port")
            corrupt_nginx_listen_port
            ;;
        "corrupt_nginx_config")
            corrupt_nginx_config
            ;;
        "block_internal_api")
            block_internal_api
            ;;
        "corrupt_ssl_config")
            corrupt_ssl_config
            ;;
        "wrong_bind_address")
            wrong_bind_address
            ;;
        "reduce_worker_processes")
            reduce_worker_processes
            ;;
        "limit_db_connections")
            limit_db_connections
            ;;
        "consume_memory")
            consume_memory
            ;;
        "slow_disk_io")
            slow_disk_io
            ;;
        "consume_cpu")
            consume_cpu
            ;;
        "fill_logs_partition")
            fill_logs_partition
            ;;
        "corrupt_gitlab_yml_syntax")
            corrupt_gitlab_yml_syntax
            ;;
        "wrong_timezone_config")
            wrong_timezone_config
            ;;
        "corrupt_gitlab_secrets")
            corrupt_gitlab_secrets
            ;;
        "wrong_service_config")
            wrong_service_config
            ;;
        "corrupt_main_config")
            corrupt_main_config
            ;;
        "corrupt_service_files")
            corrupt_service_files
            ;;
        *)
            error "Unknown corruption function: $selected_corruption"
            ;;
    esac
    
    # Restore output in mystery mode
    if [[ "$SCENARIO_SPECIFIED" != true ]]; then
        exec 1>&3 2>&4  # Restore stdout/stderr
        exec 3>&- 4>&-  # Close backup descriptors
    fi
}

disable_runner_service_temp() {
    log "Temporarily disabling GitLab Runner service"
    systemctl stop gitlab-runner || true
    # Create a temporary marker file
    touch /tmp/gitlab-chaos-runner-disabled
    success "Runner service disabled"
    echo "HINT: Check systemd service status and startup configuration" >> "$SCENARIO_LOG"
}

delete_runner_binary() {
    log "Moving GitLab Runner binary"
    if [[ -f "/usr/local/bin/gitlab-runner" ]]; then
        mv /usr/local/bin/gitlab-runner /tmp/gitlab-runner.backup
    elif [[ -f "/usr/bin/gitlab-runner" ]]; then
        mv /usr/bin/gitlab-runner /tmp/gitlab-runner.backup
    fi
    success "Runner binary moved"
    echo "HINT: Check runner binary location and PATH" >> "$SCENARIO_LOG"
}

corrupt_runner_db_entry() {
    log "Corrupting runner database entry"
    if command -v gitlab-rails >/dev/null 2>&1; then
        timeout 30 gitlab-rails runner "
            runner = Ci::Runner.first
            if runner
                runner.update_column(:token, 'corrupted-db-token-123')
                puts 'Runner token corrupted in database'
            end
        " 2>/dev/null || true
        success "Runner DB entry corrupted"
        echo "HINT: Check database vs local config token mismatch" >> "$SCENARIO_LOG"
    fi
}

corrupt_redis_config() {
    log "Corrupting Redis configuration"
    if [[ -f "$GITLAB_CONFIG" ]]; then
        echo "gitlab_rails['redis_port'] = 99999" >> "$GITLAB_CONFIG"
        gitlab-ctl reconfigure >/dev/null 2>&1 || true
        success "Redis config corrupted"
        echo "HINT: Check Redis connectivity and port configuration" >> "$SCENARIO_LOG"
    fi
}

temp_db_connection_issue() {
    if [[ "$ORIGINAL_ARGS" == *"--scenario="* ]]; then
        log "Creating temporary database connection issue"
    fi
    # Temporarily overwhelm database connections
    for i in {1..20}; do
        timeout 30 gitlab-rails runner "
            begin
                ActiveRecord::Base.connection.execute('SELECT pg_sleep(30)')
            rescue => e
                puts 'Connection error: ' + e.message
            end
        " >/dev/null 2>&1 &
    done
    if [[ "$ORIGINAL_ARGS" == *"--scenario="* ]]; then
        success "Database connection issue created"
    fi
    echo "HINT: Check database connection pool and active connections" >> "$SCENARIO_LOG"
}

corrupt_postgres_config() {
    log "Corrupting PostgreSQL configuration"
    if [[ -f "$GITLAB_CONFIG" ]]; then
        echo "postgresql['port'] = 99999" >> "$GITLAB_CONFIG"
        gitlab-ctl reconfigure >/dev/null 2>&1 || true
        success "PostgreSQL config corrupted"
        echo "HINT: Check PostgreSQL service and port configuration" >> "$SCENARIO_LOG"
    fi
}

corrupt_db_permissions() {
    log "Corrupting database file permissions"
    local postgres_data="/var/opt/gitlab/postgresql/data"
    if [[ -d "$postgres_data" ]]; then
        chmod 700 "$postgres_data" 2>/dev/null || true
        chown root:root "$postgres_data" 2>/dev/null || true
        success "Database permissions corrupted"
        echo "HINT: Check file permissions and ownership for PostgreSQL data" >> "$SCENARIO_LOG"
    fi
}

simulate_db_lock() {
    log "Simulating database lock"
    if command -v gitlab-rails >/dev/null 2>&1; then
        timeout 60 gitlab-rails runner "
            begin
                ActiveRecord::Base.connection.execute('LOCK TABLE projects IN ACCESS EXCLUSIVE MODE; SELECT pg_sleep(60);')
            rescue => e
                puts 'Lock error: ' + e.message
            end
        " >/dev/null 2>&1 &
        success "Database lock simulated"
        echo "HINT: Check for database locks and blocking queries" >> "$SCENARIO_LOG"
    fi
}

corrupt_single_repo() {
    log "Corrupting a single repository"
    local repo_path="/var/opt/gitlab/git-data/repositories"
    if [[ -d "$repo_path" ]]; then
        # Find first repository and corrupt it
        local first_repo=$(find "$repo_path" -name "*.git" -type d | head -1)
        if [[ -n "$first_repo" && -d "$first_repo" ]]; then
            rm -f "$first_repo/HEAD" 2>/dev/null || true
            success "Single repository corrupted"
            echo "HINT: Run git fsck and check repository integrity" >> "$SCENARIO_LOG"
        fi
    fi
}

wrong_storage_permissions() {
    log "Setting wrong storage permissions"
    local git_data="/var/opt/gitlab/git-data"
    if [[ -d "$git_data" ]]; then
        chmod 700 "$git_data" 2>/dev/null || true
        chown root:root "$git_data" 2>/dev/null || true
        success "Storage permissions corrupted"
        echo "HINT: Check git-data directory permissions and ownership" >> "$SCENARIO_LOG"
    fi
}

corrupt_gitaly_config() {
    log "Corrupting Gitaly configuration"
    if [[ -f "$GITLAB_CONFIG" ]]; then
        echo "gitaly['socket_path'] = ''" >> "$GITLAB_CONFIG"  # Disable socket mode
        echo "gitaly['listen_addr'] = '192.168.1.999:8075'" >> "$GITLAB_CONFIG"  # Force TCP mode
        success "Gitaly config corrupted"
        echo "HINT: Check Gitaly service connectivity and address binding" >> "$SCENARIO_LOG"
    fi
}

corrupt_multiple_repos() {
    log "Corrupting multiple repositories"
    local repo_path="/var/opt/gitlab/git-data/repositories"
    if [[ -d "$repo_path" ]]; then
        find "$repo_path" -name "*.git" -type d | head -3 | while read -r repo; do
            rm -f "$repo/refs/heads/main" "$repo/refs/heads/master" 2>/dev/null || true
        done
        success "Multiple repositories corrupted"
        echo "HINT: Check repository integrity across multiple projects" >> "$SCENARIO_LOG"
    fi
}

fill_storage_space() {
    log "Filling up storage space"
    local storage_path="/var/opt/gitlab"
    dd if=/dev/zero of="$storage_path/space-filler.tmp" bs=1M count=1000 2>/dev/null || true
    success "Storage space filled"
    echo "HINT: Check disk space usage and cleanup temporary files" >> "$SCENARIO_LOG"
}

corrupt_storage_config() {
    log "Corrupting storage configuration"
    if [[ -f "$GITLAB_CONFIG" ]]; then
        echo "git_data_dirs({'default' => {'path' => '/nonexistent/path'}})" >> "$GITLAB_CONFIG"
        gitlab-ctl reconfigure >/dev/null 2>&1 || true
        success "Storage config corrupted"
        echo "HINT: Check git data directory configuration and paths" >> "$SCENARIO_LOG"
    fi
}

corrupt_git_storage_path() {
    log "Corrupting git storage path"
    local git_data="/var/opt/gitlab/git-data"
    if [[ -d "$git_data" ]]; then
        mv "$git_data" "$git_data.corrupted" 2>/dev/null || true
        success "Git storage path corrupted"
        echo "HINT: Check git data directory existence and configuration" >> "$SCENARIO_LOG"
    fi
}

corrupt_nginx_listen_port() {
    log "Corrupting nginx listen port"
    if [[ -f "$GITLAB_CONFIG" ]]; then
        echo "nginx['listen_port'] = 99999" >> "$GITLAB_CONFIG"
        gitlab-ctl reconfigure >/dev/null 2>&1 || true
        success "Nginx port corrupted"
        echo "HINT: Check nginx configuration and port binding" >> "$SCENARIO_LOG"
    fi
}

corrupt_nginx_config() {
    log "Corrupting nginx configuration"
    local nginx_conf="/var/opt/gitlab/nginx/conf/gitlab-http.conf"
    if [[ -f "$nginx_conf" ]]; then
        echo "invalid_nginx_directive = broken;" >> "$nginx_conf"
        gitlab-ctl restart nginx >/dev/null 2>&1 || true
        success "Nginx config corrupted"
        echo "HINT: Check nginx configuration syntax and service status" >> "$SCENARIO_LOG"
    fi
}

block_internal_api() {
    log "Blocking internal API access"
    if command -v iptables >/dev/null 2>&1; then
        iptables -A INPUT -p tcp --dport 8080 -j DROP 2>/dev/null || true
        success "Internal API blocked"
        echo "HINT: Check firewall rules and internal service connectivity" >> "$SCENARIO_LOG"
    fi
}

corrupt_ssl_config() {
    log "Corrupting SSL configuration"
    if [[ -f "$GITLAB_CONFIG" ]]; then
        echo "nginx['ssl_certificate'] = '/nonexistent/cert.pem'" >> "$GITLAB_CONFIG"
        echo "nginx['ssl_certificate_key'] = '/nonexistent/key.pem'" >> "$GITLAB_CONFIG"
        gitlab-ctl reconfigure >/dev/null 2>&1 || true
        success "SSL config corrupted"
        echo "HINT: Check SSL certificate paths and validity" >> "$SCENARIO_LOG"
    fi
}

wrong_bind_address() {
    log "Setting wrong bind address"
    if [[ -f "$GITLAB_CONFIG" ]]; then
        echo "nginx['listen_addresses'] = ['192.168.1.999']" >> "$GITLAB_CONFIG"
        gitlab-ctl reconfigure >/dev/null 2>&1 || true
        success "Bind address corrupted"
        echo "HINT: Check network interface binding and IP configuration" >> "$SCENARIO_LOG"
    fi
}

reduce_worker_processes() {
    log "Reducing worker processes"
    if [[ -f "$GITLAB_CONFIG" ]]; then
        echo "unicorn['worker_processes'] = 1" >> "$GITLAB_CONFIG"
        echo "sidekiq['max_concurrency'] = 1" >> "$GITLAB_CONFIG"
        gitlab-ctl reconfigure >/dev/null 2>&1 || true
        success "Worker processes reduced"
        echo "HINT: Check worker configuration and performance impact" >> "$SCENARIO_LOG"
    fi
}

limit_db_connections() {
    log "Limiting database connections"
    if [[ -f "$GITLAB_CONFIG" ]]; then
        echo "postgresql['max_connections'] = 5" >> "$GITLAB_CONFIG"
        gitlab-ctl reconfigure >/dev/null 2>&1 || true
        success "Database connections limited"
        echo "HINT: Check database connection limits and pool configuration" >> "$SCENARIO_LOG"
    fi
}

slow_disk_io() {
    if [[ "$ORIGINAL_ARGS" == *"--scenario="* ]]; then
        log "Slowing disk I/O"
    fi
    # Create a background process that does intensive I/O
    (
        while true; do
            dd if=/dev/zero of=/tmp/io-stress bs=1M count=100 oflag=direct 2>/dev/null
            rm -f /tmp/io-stress
            sleep 1
        done &
        echo $! > /tmp/gitlab-chaos-io-stress.pid
    )
    if [[ "$ORIGINAL_ARGS" == *"--scenario="* ]]; then
        success "Disk I/O stress started"
    fi
    echo "HINT: Check disk I/O performance and system load" >> "$SCENARIO_LOG"
}

consume_cpu() {
    log "Consuming CPU resources"
    # Start CPU-intensive background processes
    for ((i=1; i<=4; i++)); do
        (while true; do :; done) &
        echo $! >> /tmp/gitlab-chaos-cpu-hogs.pid
    done
    success "CPU consumption started"
    echo "HINT: Check CPU usage and system performance" >> "$SCENARIO_LOG"
}

corrupt_gitlab_yml_syntax() {
    log "Corrupting GitLab configuration values"
    if [[ -f "$GITLAB_CONFIG" ]]; then
        # Instead of breaking syntax, use invalid but parseable values
        echo "gitlab_rails['time_zone'] = 'Invalid/Timezone'" >> "$GITLAB_CONFIG"
        echo "nginx['worker_processes'] = -1" >> "$GITLAB_CONFIG"
        success "Configuration values corrupted"
        echo "HINT: Check configuration file values and service startup" >> "$SCENARIO_LOG"
    fi
}

wrong_timezone_config() {
    log "Setting wrong timezone configuration"
    if [[ -f "$GITLAB_CONFIG" ]]; then
        echo "gitlab_rails['time_zone'] = 'NonExistent/Timezone'" >> "$GITLAB_CONFIG"
        success "Timezone config corrupted"
        echo "HINT: Check timezone configuration and system time settings" >> "$SCENARIO_LOG"
    fi
}

wrong_service_config() {
    log "Setting wrong service configuration"
    if [[ -f "$GITLAB_CONFIG" ]]; then
        echo "gitlab_rails['gitlab_shell_ssh_port'] = 99999" >> "$GITLAB_CONFIG"
        gitlab-ctl reconfigure >/dev/null 2>&1 || true
        success "Service config corrupted"
        echo "HINT: Check service port configuration and connectivity" >> "$SCENARIO_LOG"
    fi
}

corrupt_main_config() {
    log "Corrupting main configuration settings"
    if [[ -f "$GITLAB_CONFIG" ]]; then
        # Use invalid but syntactically correct configurations
        echo "external_url 'http://invalid-hostname-that-does-not-exist.local'" >> "$GITLAB_CONFIG"
        echo "gitlab_rails['gitlab_shell_ssh_port'] = 99999" >> "$GITLAB_CONFIG"
        success "Main config corrupted"
        echo "HINT: Check configuration values and service connectivity" >> "$SCENARIO_LOG"
    fi
}

corrupt_service_files() {
    log "Corrupting systemd service files"
    local service_file="/etc/systemd/system/gitlab-runsvdir.service"
    if [[ -f "$service_file" ]]; then
        echo "InvalidDirective=broken" >> "$service_file"
        systemctl daemon-reload 2>/dev/null || true
        success "Service files corrupted"
        echo "HINT: Check systemd service configuration and status" >> "$SCENARIO_LOG"
    fi
}
corrupt_runner_token() {
    if [[ "$ORIGINAL_ARGS" == *"--scenario="* ]]; then
        log "Corrupting GitLab Runner token"
    fi
    if [[ -f "$RUNNER_CONFIG" ]]; then
        local bad_token="glrt-corrupted-token-$(date +%s)"
        sed -i "s/glrt-[A-Za-z0-9._-]*/${bad_token}/" "$RUNNER_CONFIG"
        systemctl restart gitlab-runner || true
        if [[ "$ORIGINAL_ARGS" == *"--scenario="* ]]; then
            success "Runner token corrupted"
        fi
        echo "HINT: Check runner authentication and token validation" >> "$SCENARIO_LOG"
    fi
}

corrupt_runner_config() {
    log "Corrupting runner configuration file"
    if [[ -f "$RUNNER_CONFIG" ]]; then
        # Add invalid configuration
        echo -e "\n[runners.docker]\n  invalid_option = \"corrupt_value\"" >> "$RUNNER_CONFIG"
        # Corrupt URL
        sed -i 's|url = .*|url = "http://invalid-gitlab-url:8080/"|' "$RUNNER_CONFIG"
        systemctl restart gitlab-runner || true
        success "Runner config corrupted"
        echo "HINT: Validate runner configuration syntax and connectivity" >> "$SCENARIO_LOG"
    fi
}

wrong_runner_url() {
    log "Setting wrong GitLab URL in runner config"
    if [[ -f "$RUNNER_CONFIG" ]]; then
        sed -i 's|url = .*|url = "http://192.168.1.999:8080/"|' "$RUNNER_CONFIG"
        systemctl restart gitlab-runner || true
        success "Runner URL corrupted"
        echo "HINT: Check network connectivity and URL configuration" >> "$SCENARIO_LOG"
    fi
}

corrupt_db_password() {
    if [[ "$ORIGINAL_ARGS" == *"--scenario="* ]]; then
        log "Corrupting database password"
    fi
    if [[ -f "$GITLAB_CONFIG" ]]; then
        sed -i "s/gitlab_rails\['db_password'\] = .*/gitlab_rails['db_password'] = 'wrong_password'/" "$GITLAB_CONFIG"
        gitlab-ctl reconfigure >/dev/null 2>&1 || true
        if [[ "$ORIGINAL_ARGS" == *"--scenario="* ]]; then
            success "Database password corrupted"
        fi
        echo "HINT: Check database connectivity and authentication" >> "$SCENARIO_LOG"
    fi
}

wrong_external_url() {
    log "Setting wrong external URL"
    if [[ -f "$GITLAB_CONFIG" ]]; then
        sed -i "s|external_url .*|external_url 'http://wrong-hostname.invalid'|" "$GITLAB_CONFIG"
        gitlab-ctl reconfigure >/dev/null 2>&1 || true
        success "External URL corrupted"
        echo "HINT: Check URL configuration and DNS resolution" >> "$SCENARIO_LOG"
    fi
}

corrupt_gitlab_secrets() {
    log "Corrupting GitLab secrets"
    if [[ -f "$GITLAB_HOME/gitlab-secrets.json" ]]; then
        # Corrupt a random secret
        sed -i 's/"secret_key_base": "[^"]*"/"secret_key_base": "corrupted_secret_key"/' "$GITLAB_HOME/gitlab-secrets.json"
        gitlab-ctl restart >/dev/null 2>&1 || true
        success "GitLab secrets corrupted"
        echo "HINT: Check application secrets and session management" >> "$SCENARIO_LOG"
    fi
}

corrupt_memory_settings() {
    log "Setting unrealistic memory configurations"
    if [[ -f "$GITLAB_CONFIG" ]]; then
        echo "postgresql['shared_buffers'] = '50GB'" >> "$GITLAB_CONFIG"
        echo "redis['maxmemory'] = '20GB'" >> "$GITLAB_CONFIG"
        success "Memory settings corrupted"
        echo "HINT: Check memory allocation and system resources" >> "$SCENARIO_LOG"
    fi
}

corrupt_worker_settings() {
    log "Setting problematic worker configurations"
    if [[ -f "$GITLAB_CONFIG" ]]; then
        echo "puma['worker_processes'] = 50" >> "$GITLAB_CONFIG"
        echo "sidekiq['concurrency'] = 200" >> "$GITLAB_CONFIG"
        success "Worker settings corrupted"
        echo "HINT: Check worker process configuration and system load" >> "$SCENARIO_LOG"
    fi
}

corrupt_ssl_redirect() {
    log "Enabling problematic SSL redirect"
    if [[ -f "$GITLAB_CONFIG" ]]; then
        echo "nginx['redirect_http_to_https'] = true" >> "$GITLAB_CONFIG"
        echo "nginx['ssl_certificate'] = '/etc/ssl/certs/nonexistent.crt'" >> "$GITLAB_CONFIG"
        success "SSL redirect corrupted"
        echo "HINT: Check SSL configuration and certificate paths" >> "$SCENARIO_LOG"
    fi
}

corrupt_gitaly_socket() {
    log "Corrupting Gitaly socket path"
    if [[ -f "$GITLAB_CONFIG" ]]; then
        echo "gitaly['socket_path'] = '/tmp/nonexistent/path/gitaly.socket'" >> "$GITLAB_CONFIG"
        success "Gitaly socket corrupted"
        echo "HINT: Check Gitaly socket connectivity and file permissions" >> "$SCENARIO_LOG"
    fi
}

consume_memory() {
    log "Consuming system memory"
    # Create a background process that consumes memory
    (
        python3 -c "
import time
memory_hog = []
try:
    while True:
        memory_hog.append(' ' * 1024 * 1024)  # 1MB chunks
        time.sleep(0.1)
        if len(memory_hog) > 1000:  # Limit to ~1GB
            break
except KeyboardInterrupt:
    pass
" &
        echo $! > /tmp/gitlab-chaos-memory-hog.pid
    )
    success "Memory consumption started"
    echo "HINT: Check system memory usage and GitLab service health" >> "$SCENARIO_LOG"
}

fill_temp_space() {
    mystery_log "Filling logs partition"
    local log_file="/var/log/gitlab/chaos-filler.log"
    # Create a large log file
    dd if=/dev/zero of="$log_file" bs=1M count=500 2>/dev/null || true
    mystery_success "Logs partition filled"
    echo "HINT: Check disk space and log rotation" >> "$SCENARIO_LOG"
}

# Main execution function
main() {
    echo -e "${PURPLE}
    ╔═══════════════════════════════════════════╗
    ║        GitLab Chaos Engineering           ║
    ║     Dullbox Troubleshooting Practice      ║
    ╚═══════════════════════════════════════════╝
    ${NC}"
    
    # Store original arguments for checking later
    ORIGINAL_ARGS="$*"
    
    check_root
    setup_backup_dir
    parse_args "$@"
    
    # Determine scenario and severity
    if [[ -z "$SCENARIO" || "$SCENARIO" == "random" ]]; then
        local scenarios=("runner" "database" "storage" "network" "performance" "config")
        SCENARIO=${scenarios[$RANDOM % ${#scenarios[@]}]}
    fi
    
    if [[ "$SEVERITY" == "random" ]]; then
        local severities=("low" "medium" "high")
        SEVERITY=${severities[$RANDOM % ${#severities[@]}]}
    fi
    
    # Only log scenario details if explicitly specified by user
    if [[ "$SCENARIO_SPECIFIED" == true ]]; then
        log "Selected scenario: $SCENARIO (severity: $SEVERITY)"
    else
        log "Chaos scenario initiated (severity: $SEVERITY)"
        warning "Investigation mode: who knows ooOoOOOo"
    fi
    
    if [[ "$DRY_RUN" == false ]]; then
        create_backups
    fi
    
    generate_corruption "$SCENARIO" "$SEVERITY"

    if [[ "$DRY_RUN" == false ]]; then
    log "Applying configuration changes..."
    if gitlab-ctl reconfigure >/dev/null 2>&1; then
        success "Configuration changes applied"
    else
        warning "Configuration reconfigure failed - some changes may not be active"
    fi
fi
    
    echo -e "\n${CYAN}════════════════════════════════════════════${NC}"
    echo -e "${GREEN}Chaos scenario deployed successfully!${NC}"
    echo -e "${CYAN}════════════════════════════════════════════${NC}"
    
    # Only show scenario details if explicitly specified
    if [[ "$SCENARIO_SPECIFIED" == true ]]; then
        echo -e "Scenario: ${YELLOW}$SCENARIO${NC}"
        echo -e "Severity: ${YELLOW}$SEVERITY${NC}"
    else
        echo -e "Mode: ${YELLOW}Mystery Investigation${NC}"
        echo -e "Severity: ${YELLOW}$SEVERITY${NC}"
        echo -e "${PURPLE} Figure out what broke!${NC}"
    fi
    
    echo -e "Log file: ${BLUE}$SCENARIO_LOG${NC}"
    echo -e "\n${PURPLE}Happy troubleshooting! ${NC}"
    echo -e "\nTo restore: Use backups in ${BLUE}$BACKUP_DIR${NC}"
}

# Handle special arguments
if [[ "${1:-}" == "--restore" ]]; then
    # Restoration logic would go here
    echo "Restoration feature not yet implemented"
    exit 0
elif [[ "${1:-}" == "--status" ]]; then
    # Status checking logic would go here
    echo "Status checking feature not yet implemented"
    exit 0
fi

# Run main function
main "$@"