<?php
/**
 * ============================================================================
 * classes/Encryption.php - End-to-End Encryption Handler
 * ============================================================================
 */

namespace App;

use Exception;

class Encryption {
    
    /**
     * Generate RSA key pair for end-to-end encryption
     */
    public static function generateKeyPair() {
        $config = [
            'private_key_bits' => 2048,
            'private_key_type' => OPENSSL_KEYTYPE_RSA,
        ];
        
        $res = openssl_pkey_new($config);
        if ($res === false) {
            throw new Exception('Failed to generate key pair');
        }
        
        // Extract private key
        openssl_pkey_export($res, $privateKey);
        
        // Extract public key
        $keyDetails = openssl_pkey_get_details($res);
        $publicKey = $keyDetails['key'];
        
        return [
            'private_key' => $privateKey,
            'public_key' => $publicKey
        ];
    }
    
    /**
     * Encrypt private key with user's password
     */
    public static function encryptPrivateKey($privateKey, $password) {
        // Generate salt
        $salt = random_bytes(32);
        
        // Derive key from password using PBKDF2
        $key = hash_pbkdf2('sha256', $password, $salt, 100000, 32, true);
        
        // Generate IV
        $iv = random_bytes(16);
        
        // Encrypt private key
        $encryptedKey = openssl_encrypt(
            $privateKey,
            'AES-256-CBC',
            $key,
            OPENSSL_RAW_DATA,
            $iv
        );
        
        if ($encryptedKey === false) {
            throw new Exception('Failed to encrypt private key');
        }
        
        return [
            'encrypted_key' => base64_encode($encryptedKey),
            'salt' => base64_encode($salt),
            'iv' => base64_encode($iv)
        ];
    }
    
    /**
     * Decrypt private key with user's password
     */
    public static function decryptPrivateKey($encryptedData, $password) {
        try {
            $encryptedKey = base64_decode($encryptedData['encrypted_key']);
            $salt = base64_decode($encryptedData['salt']);
            $iv = base64_decode($encryptedData['iv']);
            
            // Derive key from password
            $key = hash_pbkdf2('sha256', $password, $salt, 100000, 32, true);
            
            // Decrypt private key
            $privateKey = openssl_decrypt(
                $encryptedKey,
                'AES-256-CBC',
                $key,
                OPENSSL_RAW_DATA,
                $iv
            );
            
            if ($privateKey === false) {
                return false;
            }
            
            return $privateKey;
        } catch (Exception $e) {
            error_log('Decryption error: ' . $e->getMessage());
            return false;
        }
    }
    
    /**
     * Encrypt message for a recipient
     */
    public static function encryptMessage($message, $publicKey) {
        // Generate random AES key for message
        $messageKey = random_bytes(32);
        $iv = random_bytes(16);
        
        // Encrypt message with AES
        $encryptedMessage = openssl_encrypt(
            $message,
            'AES-256-CBC',
            $messageKey,
            OPENSSL_RAW_DATA,
            $iv
        );
        
        if ($encryptedMessage === false) {
            throw new Exception('Failed to encrypt message');
        }
        
        // Encrypt the AES key with recipient's public key
        $encryptedKey = '';
        $success = openssl_public_encrypt(
            $messageKey,
            $encryptedKey,
            $publicKey,
            OPENSSL_PKCS1_OAEP_PADDING
        );
        
        if (!$success) {
            throw new Exception('Failed to encrypt message key');
        }
        
        return [
            'encrypted_message' => base64_encode($encryptedMessage),
            'encrypted_key' => base64_encode($encryptedKey),
            'iv' => base64_encode($iv)
        ];
    }
    
    /**
     * Decrypt message with private key
     */
    public static function decryptMessage($encryptedData, $privateKey) {
        try {
            $encryptedMessage = base64_decode($encryptedData['encrypted_message']);
            $encryptedKey = base64_decode($encryptedData['encrypted_key']);
            $iv = base64_decode($encryptedData['iv']);
            
            // Decrypt the AES key with private key
            $messageKey = '';
            $success = openssl_private_decrypt(
                $encryptedKey,
                $messageKey,
                $privateKey,
                OPENSSL_PKCS1_OAEP_PADDING
            );
            
            if (!$success) {
                return false;
            }
            
            // Decrypt message with AES key
            $message = openssl_decrypt(
                $encryptedMessage,
                'AES-256-CBC',
                $messageKey,
                OPENSSL_RAW_DATA,
                $iv
            );
            
            return $message;
        } catch (Exception $e) {
            error_log('Message decryption error: ' . $e->getMessage());
            return false;
        }
    }
    
    /**
     * Encrypt message for multiple recipients (group chat)
     */
    public static function encryptForMultipleRecipients($message, $publicKeys) {
        // Generate random AES key for message
        $messageKey = random_bytes(32);
        $iv = random_bytes(16);
        
        // Encrypt message with AES
        $encryptedMessage = openssl_encrypt(
            $message,
            'AES-256-CBC',
            $messageKey,
            OPENSSL_RAW_DATA,
            $iv
        );
        
        if ($encryptedMessage === false) {
            throw new Exception('Failed to encrypt message');
        }
        
        // Encrypt the AES key for each recipient
        $encryptedKeys = [];
        foreach ($publicKeys as $userId => $publicKey) {
            $encryptedKey = '';
            $success = openssl_public_encrypt(
                $messageKey,
                $encryptedKey,
                $publicKey,
                OPENSSL_PKCS1_OAEP_PADDING
            );
            
            if ($success) {
                $encryptedKeys[$userId] = base64_encode($encryptedKey);
            }
        }
        
        return [
            'encrypted_message' => base64_encode($encryptedMessage),
            'encrypted_keys' => $encryptedKeys,
            'iv' => base64_encode($iv)
        ];
    }
    
    /**
     * Sign message with private key
     */
    public static function signMessage($message, $privateKey) {
        $signature = '';
        $success = openssl_sign($message, $signature, $privateKey, OPENSSL_ALGO_SHA256);
        
        if (!$success) {
            throw new Exception('Failed to sign message');
        }
        
        return base64_encode($signature);
    }
    
    /**
     * Verify message signature
     */
    public static function verifySignature($message, $signature, $publicKey) {
        $signature = base64_decode($signature);
        $result = openssl_verify($message, $signature, $publicKey, OPENSSL_ALGO_SHA256);
        
        return $result === 1;
    }
    
    /**
     * Generate message hash
     */
    public static function hashMessage($message) {
        return hash('sha256', $message);
    }
    
    /**
     * Generate fingerprint from public key
     */
    public static function generateFingerprint($publicKey) {
        return hash('sha256', $publicKey);
    }
}