#!/bin/bash

# WHP Encryption Key Rotation Script
# Rotates the encryption key and re-encrypts all stored passwords

set -e

KEY_FILE="/etc/whp/encryption.key"
BACKUP_DIR="/root/whp-key-backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

echo "🔄 WHP Encryption Key Rotation"
echo "=============================="

# Check if running as root
if [ "$EUID" -ne 0 ]; then
    echo "❌ This script must be run as root"
    exit 1
fi

# Check if encryption key exists
if [ ! -f "$KEY_FILE" ]; then
    echo "❌ Encryption key not found: $KEY_FILE"
    echo "   Run update-add-encryption.sh first"
    exit 1
fi

# Create backup directory
mkdir -p "$BACKUP_DIR"

# Step 1: Backup database before rotation
echo "📦 Creating database backup before key rotation..."
DB_BACKUP_FILE="$BACKUP_DIR/whp_database_pre_rotation_$TIMESTAMP.sql"
mysqldump whp > "$DB_BACKUP_FILE"
if [ $? -eq 0 ]; then
    echo "✅ Database backed up to: $DB_BACKUP_FILE"
else
    echo "❌ Database backup failed! Aborting key rotation."
    exit 1
fi

# Step 2: Backup current key
echo "📦 Backing up current encryption key..."
cp "$KEY_FILE" "$BACKUP_DIR/encryption.key.backup.$TIMESTAMP"
echo "✅ Current key backed up to: $BACKUP_DIR/encryption.key.backup.$TIMESTAMP"

# Step 3: Generate new key
echo "🔑 Generating new encryption key..."
NEW_KEY=$(openssl rand -base64 32)
echo "$NEW_KEY" > "${KEY_FILE}.new"
chmod 600 "${KEY_FILE}.new"
chown root:root "${KEY_FILE}.new"

# Step 4: Get all users with encrypted passwords
echo "🔍 Finding users with stored passwords..."
USERS=$(mysql -N -e "SELECT username FROM whp.user_passwords WHERE mysql_password IS NOT NULL AND mysql_password != ''")

if [ -z "$USERS" ]; then
    echo "ℹ️  No users found with stored passwords"
    # Just replace the key file
    mv "${KEY_FILE}.new" "$KEY_FILE"
    echo "✅ Key rotation complete (no passwords to re-encrypt)"
    exit 0
fi

echo "🔄 Re-encrypting passwords with new key..."

ROTATED=0
FAILED=0

for USERNAME in $USERS; do
    echo -n "   Processing $USERNAME... "
    
    # Get current encrypted password
    CURRENT_ENCRYPTED=$(mysql -N -e "SELECT mysql_password FROM whp.user_passwords WHERE username = '$USERNAME'")
    
    if [ -n "$CURRENT_ENCRYPTED" ]; then
        # Decrypt with old key
        PLAINTEXT=$(php -r "
            \$keyFile = '$KEY_FILE';
            \$encryptedPassword = '$CURRENT_ENCRYPTED';
            
            if (!file_exists(\$keyFile)) {
                echo 'ERROR: Key file not found';
                exit(1);
            }
            
            try {
                \$key = base64_decode(trim(file_get_contents(\$keyFile)));
                \$data = base64_decode(\$encryptedPassword);
                
                // Check if this looks like encrypted data
                if (strlen(\$data) < 28) {
                    // Legacy base64 encoded password
                    echo base64_decode(\$encryptedPassword);
                    exit(0);
                }
                
                \$iv = substr(\$data, 0, 12);
                \$tag = substr(\$data, 12, 16);
                \$encrypted = substr(\$data, 28);
                
                \$decrypted = openssl_decrypt(\$encrypted, 'aes-256-gcm', \$key, OPENSSL_RAW_DATA, \$iv, \$tag);
                
                if (\$decrypted === false) {
                    echo 'ERROR: Decryption failed';
                    exit(1);
                }
                
                echo \$decrypted;
            } catch (Exception \$e) {
                echo 'ERROR: ' . \$e->getMessage();
                exit(1);
            }
        ")
        
        if [[ $PLAINTEXT == ERROR:* ]]; then
            echo "❌ Decryption failed - ${PLAINTEXT#ERROR: }"
            ((FAILED++))
            continue
        fi
        
        # Encrypt with new key
        NEW_ENCRYPTED=$(php -r "
            \$keyFile = '${KEY_FILE}.new';
            \$password = '$PLAINTEXT';
            
            if (!file_exists(\$keyFile)) {
                echo 'ERROR: New key file not found';
                exit(1);
            }
            
            try {
                \$key = base64_decode(trim(file_get_contents(\$keyFile)));
                \$iv = random_bytes(12);
                \$encrypted = openssl_encrypt(\$password, 'aes-256-gcm', \$key, OPENSSL_RAW_DATA, \$iv, \$tag);
                
                if (\$encrypted === false) {
                    echo 'ERROR: Encryption failed';
                    exit(1);
                }
                
                echo base64_encode(\$iv . \$tag . \$encrypted);
            } catch (Exception \$e) {
                echo 'ERROR: ' . \$e->getMessage();
                exit(1);
            }
        ")
        
        if [[ $NEW_ENCRYPTED == ERROR:* ]]; then
            echo "❌ Re-encryption failed - ${NEW_ENCRYPTED#ERROR: }"
            ((FAILED++))
            continue
        fi
        
        # Update database with new encrypted password
        mysql -e "UPDATE whp.user_passwords SET mysql_password = '$NEW_ENCRYPTED' WHERE username = '$USERNAME'"
        if [ $? -eq 0 ]; then
            echo "✅ Re-encrypted"
            ((ROTATED++))
        else
            echo "❌ Database update failed"
            ((FAILED++))
        fi
    else
        echo "⚠️  No password found"
    fi
done

# Handle PostgreSQL passwords if any exist
PG_USERS=$(mysql -N -e "SELECT username FROM whp.user_passwords WHERE postgresql_password IS NOT NULL AND postgresql_password != ''")

if [ -n "$PG_USERS" ]; then
    echo "🔄 Re-encrypting PostgreSQL passwords..."
    
    for USERNAME in $PG_USERS; do
        echo -n "   Processing PostgreSQL password for $USERNAME... "
        
        CURRENT_PG_ENCRYPTED=$(mysql -N -e "SELECT postgresql_password FROM whp.user_passwords WHERE username = '$USERNAME'")
        
        if [ -n "$CURRENT_PG_ENCRYPTED" ]; then
            # Decrypt with old key (reuse same logic)
            PG_PLAINTEXT=$(php -r "
                \$keyFile = '$KEY_FILE';
                \$encryptedPassword = '$CURRENT_PG_ENCRYPTED';
                
                try {
                    \$key = base64_decode(trim(file_get_contents(\$keyFile)));
                    \$data = base64_decode(\$encryptedPassword);
                    
                    if (strlen(\$data) < 28) {
                        echo base64_decode(\$encryptedPassword);
                        exit(0);
                    }
                    
                    \$iv = substr(\$data, 0, 12);
                    \$tag = substr(\$data, 12, 16);
                    \$encrypted = substr(\$data, 28);
                    
                    \$decrypted = openssl_decrypt(\$encrypted, 'aes-256-gcm', \$key, OPENSSL_RAW_DATA, \$iv, \$tag);
                    
                    if (\$decrypted === false) {
                        echo 'ERROR: Decryption failed';
                        exit(1);
                    }
                    
                    echo \$decrypted;
                } catch (Exception \$e) {
                    echo 'ERROR: ' . \$e->getMessage();
                    exit(1);
                }
            ")
            
            if [[ $PG_PLAINTEXT == ERROR:* ]]; then
                echo "❌ Failed"
                continue
            fi
            
            # Encrypt with new key
            NEW_PG_ENCRYPTED=$(php -r "
                \$keyFile = '${KEY_FILE}.new';
                \$password = '$PG_PLAINTEXT';
                
                try {
                    \$key = base64_decode(trim(file_get_contents(\$keyFile)));
                    \$iv = random_bytes(12);
                    \$encrypted = openssl_encrypt(\$password, 'aes-256-gcm', \$key, OPENSSL_RAW_DATA, \$iv, \$tag);
                    echo base64_encode(\$iv . \$tag . \$encrypted);
                } catch (Exception \$e) {
                    echo 'ERROR: ' . \$e->getMessage();
                    exit(1);
                }
            ")
            
            if [[ $NEW_PG_ENCRYPTED == ERROR:* ]]; then
                echo "❌ Failed"
                continue
            fi
            
            mysql -e "UPDATE whp.user_passwords SET postgresql_password = '$NEW_PG_ENCRYPTED' WHERE username = '$USERNAME'"
            if [ $? -eq 0 ]; then
                echo "✅ Re-encrypted"
            else
                echo "❌ Failed"
            fi
        fi
    done
fi

echo ""
echo "📊 Key Rotation Summary:"
echo "   ✅ Re-encrypted: $ROTATED passwords"
echo "   ❌ Failed: $FAILED passwords"

if [ $FAILED -gt 0 ]; then
    echo ""
    echo "❌ Key rotation failed for some passwords!"
    echo "   Old key backup: $BACKUP_DIR/encryption.key.backup.$TIMESTAMP"
    echo "   New key file: ${KEY_FILE}.new"
    echo "   Current key: $KEY_FILE (unchanged)"
    echo ""
    echo "⚠️  Manual intervention required. Do not replace key until all passwords are rotated."
    exit 1
fi

# Step 5: Replace the key file
echo "🔄 Activating new encryption key..."
mv "$KEY_FILE" "$KEY_FILE.old"
mv "${KEY_FILE}.new" "$KEY_FILE"

echo ""
echo "🎉 Encryption key rotation complete!"
echo ""
echo "📋 Summary:"
echo "   🔑 New key: $KEY_FILE"
echo "   📦 Old key backup: $BACKUP_DIR/encryption.key.backup.$TIMESTAMP"
echo "   💾 Database backup: $DB_BACKUP_FILE"
echo "   🔄 Passwords re-encrypted: $ROTATED"
echo ""
echo "⚠️  CRITICAL: Download and securely store the new encryption key!"
echo "📋 New key content: $NEW_KEY"
echo ""
echo "🧹 IMPORTANT: After verifying that everything works correctly:"
echo "   1. Test user logins to ensure passwords are working"
echo "   2. Verify database operations are functioning"
echo "   3. Once confirmed, remove the database backup:"
echo "      rm $DB_BACKUP_FILE"
echo ""
echo "⚠️  Keep the old key backup ($BACKUP_DIR/encryption.key.backup.$TIMESTAMP) for emergency recovery"