<?php
/**
 * ============================================================================
 * classes/Encryption.php - FINAL FIX for Your System
 * ============================================================================
 */

namespace App;

class Encryption {
    
    /**
     * Generate RSA key pair for user
     * FIXED: Correct OpenSSL path for your XAMPP installation
     */
    public static function generateKeyPair() {
        try {
            // Clear any previous OpenSSL errors
            while ($msg = openssl_error_string()) {
                // Clear error queue
            }
            
            // SET THE CORRECT PATH FOR YOUR SYSTEM
            putenv('OPENSSL_CONF=C:/Server/xampp/apache/conf/openssl.cnf');
            
            // Verify the file exists
            $configPath = 'C:/Server/xampp/apache/conf/openssl.cnf';
            if (!file_exists($configPath)) {
                error_log("WARNING: openssl.cnf not found at: $configPath");
                
                // Try alternative locations
                $alternatives = [
                    'C:/Server/xampp/php/extras/openssl/openssl.cnf',
                    'C:/Server/xampp/apache/conf/extra/openssl.cnf'
                ];
                
                foreach ($alternatives as $altPath) {
                    if (file_exists($altPath)) {
                        putenv("OPENSSL_CONF=$altPath");
                        error_log("Using alternative config: $altPath");
                        break;
                    }
                }
            } else {
                error_log("Using OpenSSL config: $configPath");
            }
            
            $config = [
                "digest_alg" => "sha512",
                "private_key_bits" => 2048,
                "private_key_type" => OPENSSL_KEYTYPE_RSA,
            ];
            
            error_log("Attempting to generate RSA key pair...");
            
            // Create the private and public key
            $res = openssl_pkey_new($config);
            
            if ($res === false) {
                $errors = [];
                while ($msg = openssl_error_string()) {
                    $errors[] = $msg;
                }
                error_log('OpenSSL key generation failed: ' . implode(' | ', $errors));
                return false;
            }
            
            error_log("Key resource created successfully");
            
            // Extract the private key
            $privateKey = '';
            $exportSuccess = openssl_pkey_export($res, $privateKey);
            
            if (!$exportSuccess) {
                $errors = [];
                while ($msg = openssl_error_string()) {
                    $errors[] = $msg;
                }
                error_log('Private key export failed: ' . implode(' | ', $errors));
                return false;
            }
            
            error_log("Private key exported successfully");
            
            // Extract the public key
            $keyDetails = openssl_pkey_get_details($res);
            
            if (!$keyDetails || !isset($keyDetails["key"])) {
                error_log('Failed to get public key details');
                return false;
            }
            
            $publicKey = $keyDetails["key"];
            
            error_log("Public key extracted successfully");
            
            // Validate keys
            if (empty($privateKey) || empty($publicKey)) {
                error_log('Generated keys are empty');
                return false;
            }
            
            // Verify keys are valid PEM format
            if (strpos($privateKey, '-----BEGIN PRIVATE KEY-----') === false) {
                error_log('Private key is not in valid PEM format');
                return false;
            }
            
            if (strpos($publicKey, '-----BEGIN PUBLIC KEY-----') === false) {
                error_log('Public key is not in valid PEM format');
                return false;
            }
            
            error_log('✅ Successfully generated RSA key pair');
            error_log('   Private key length: ' . strlen($privateKey) . ' bytes');
            error_log('   Public key length: ' . strlen($publicKey) . ' bytes');
            
            return [
                'public_key' => $publicKey,
                'private_key' => $privateKey
            ];
            
        } catch (\Exception $e) {
            error_log('Exception in generateKeyPair: ' . $e->getMessage());
            error_log('Stack trace: ' . $e->getTraceAsString());
            return false;
        }
    }
    
    /**
     * Encrypt user's private key with their password
     */
    public static function encryptPrivateKey($privateKey, $password) {
        try {
            // Generate a random salt
            $salt = random_bytes(32);
            
            // Derive encryption key from password using PBKDF2
            $derivedKey = hash_pbkdf2("sha256", $password, $salt, 100000, 32, true);
            
            // Generate random IV
            $iv = random_bytes(16);
            
            // Encrypt the private key
            $encryptedKey = openssl_encrypt(
                $privateKey,
                'AES-256-CBC',
                $derivedKey,
                0,
                $iv
            );
            
            if ($encryptedKey === false) {
                $errors = [];
                while ($msg = openssl_error_string()) {
                    $errors[] = $msg;
                }
                error_log('Private key encryption failed: ' . implode(' | ', $errors));
                return false;
            }
            
            return [
                'encrypted_key' => base64_encode($encryptedKey),
                'salt' => base64_encode($salt),
                'iv' => base64_encode($iv)
            ];
            
        } catch (\Exception $e) {
            error_log('Exception in encryptPrivateKey: ' . $e->getMessage());
            return false;
        }
    }
    
    /**
     * Decrypt user's private key with their 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 the same encryption key from password
            $derivedKey = hash_pbkdf2("sha256", $password, $salt, 100000, 32, true);
            
            // Decrypt the private key
            $privateKey = openssl_decrypt(
                $encryptedKey,
                'AES-256-CBC',
                $derivedKey,
                0,
                $iv
            );
            
            if ($privateKey === false) {
                error_log('Private key decryption failed: ' . openssl_error_string());
                return false;
            }
            
            return $privateKey;
            
        } catch (\Exception $e) {
            error_log('Private key decryption error: ' . $e->getMessage());
            return false;
        }
    }
    
    /**
     * Encrypt a message with recipient's public key
     */
    public function encryptMessage($message, $publicKey) {
        try {
            // Generate a random symmetric key for the message
            $symmetricKey = random_bytes(32);
            
            // Generate random IV
            $iv = random_bytes(16);
            
            // Encrypt the message with the symmetric key
            $encryptedMessage = openssl_encrypt(
                $message,
                'AES-256-CBC',
                $symmetricKey,
                0,
                $iv
            );
            
            if ($encryptedMessage === false) {
                error_log('Message encryption failed: ' . openssl_error_string());
                return [
                    'success' => false,
                    'message' => 'Failed to encrypt message'
                ];
            }
            
            // Encrypt the symmetric key with recipient's public key
            $encryptedKey = '';
            $success = openssl_public_encrypt(
                $symmetricKey,
                $encryptedKey,
                $publicKey,
                OPENSSL_PKCS1_OAEP_PADDING
            );
            
            if (!$success) {
                error_log('Key encryption failed: ' . openssl_error_string());
                return [
                    'success' => false,
                    'message' => 'Failed to encrypt key'
                ];
            }
            
            return [
                'success' => true,
                'encrypted_data' => base64_encode($encryptedMessage),
                'encrypted_key' => base64_encode($encryptedKey),
                'iv' => base64_encode($iv)
            ];
            
        } catch (\Exception $e) {
            error_log('Message encryption error: ' . $e->getMessage());
            return [
                'success' => false,
                'message' => $e->getMessage()
            ];
        }
    }
    
    /**
     * Decrypt a message with recipient's private key
     */
    public function decryptMessage($encryptedData, $privateKey) {
        try {
            $encryptedMessage = base64_decode($encryptedData['encrypted_message']);
            $encryptedKey = base64_decode($encryptedData['encrypted_key']);
            $iv = base64_decode($encryptedData['iv']);
            
            // Decrypt the symmetric key with private key
            $symmetricKey = '';
            $success = openssl_private_decrypt(
                $encryptedKey,
                $symmetricKey,
                $privateKey,
                OPENSSL_PKCS1_OAEP_PADDING
            );
            
            if (!$success) {
                error_log('Key decryption failed: ' . openssl_error_string());
                return false;
            }
            
            // Decrypt the message with the symmetric key
            $message = openssl_decrypt(
                $encryptedMessage,
                'AES-256-CBC',
                $symmetricKey,
                0,
                $iv
            );
            
            if ($message === false) {
                error_log('Message decryption failed: ' . openssl_error_string());
                return false;
            }
            
            return $message;
            
        } catch (\Exception $e) {
            error_log('Message decryption error: ' . $e->getMessage());
            return false;
        }
    }
    
    /**
     * Generate fingerprint for public key
     */
    public static function generateFingerprint($publicKey) {
        return hash('sha256', $publicKey);
    }
    
    /**
     * Sign message with private key (for verification)
     */
    public function signMessage($message, $privateKey) {
        try {
            $signature = '';
            $success = openssl_sign($message, $signature, $privateKey, OPENSSL_ALGO_SHA256);
            
            if (!$success) {
                error_log('Message signing failed: ' . openssl_error_string());
                return false;
            }
            
            return base64_encode($signature);
            
        } catch (\Exception $e) {
            error_log('Message signing error: ' . $e->getMessage());
            return false;
        }
    }
    
    /**
     * Verify message signature
     */
    public function verifySignature($message, $signature, $publicKey) {
        try {
            $signature = base64_decode($signature);
            
            $result = openssl_verify(
                $message,
                $signature,
                $publicKey,
                OPENSSL_ALGO_SHA256
            );
            
            return $result === 1;
            
        } catch (\Exception $e) {
            error_log('Signature verification error: ' . $e->getMessage());
            return false;
        }
    }
}