<?php
/**
 * Encryption Service
 * Handles AES-256 encryption/decryption for PII data
 * Kenyan Pension & Life Insurance Management System
 * 
 * @package Classes
 * @author Senior Fintech Engineer
 */

class EncryptionService {
    private $cipher = 'AES-256-CBC';
    private $key;
    private $iv;
    
    /**
     * Constructor
     * Initialize encryption key from config or environment
     */
    public function __construct() {
        // Get encryption key from config or environment variable
        // In production, store this in environment variables or secure config
        $this->key = $this->getEncryptionKey();
    }
    
    /**
     * Get encryption key
     * Priority: Environment variable > Config file > Default (for development only)
     */
    private function getEncryptionKey() {
        // Check environment variable first
        if (getenv('ENCRYPTION_KEY')) {
            return getenv('ENCRYPTION_KEY');
        }
        
        // Check config file
        if (file_exists(__DIR__ . '/../config/encryption_key.php')) {
            $config = require __DIR__ . '/../config/encryption_key.php';
            return $config['key'] ?? null;
        }
        
        // For development only - generate a key if none exists
        // In production, this should never be used
        $keyFile = __DIR__ . '/../config/.encryption_key';
        if (file_exists($keyFile)) {
            return trim(file_get_contents($keyFile));
        }
        
        // Generate and save key (development only)
        $key = bin2hex(random_bytes(32)); // 64 character hex string
        if (!is_dir(__DIR__ . '/../config')) {
            mkdir(__DIR__ . '/../config', 0755, true);
        }
        file_put_contents($keyFile, $key);
        chmod($keyFile, 0600); // Read/write for owner only
        
        return $key;
    }
    
    /**
     * Encrypt PII data
     * 
     * @param string $data Plain text data to encrypt
     * @return string Encrypted data (base64 encoded)
     */
    public function encrypt($data) {
        if (empty($data)) {
            return $data;
        }
        
        // Generate IV for each encryption
        $ivLength = openssl_cipher_iv_length($this->cipher);
        $iv = openssl_random_pseudo_bytes($ivLength);
        
        // Encrypt the data
        $encrypted = openssl_encrypt($data, $this->cipher, $this->key, 0, $iv);
        
        // Prepend IV to encrypted data and encode
        return base64_encode($iv . $encrypted);
    }
    
    /**
     * Decrypt PII data
     * 
     * @param string $encryptedData Encrypted data (base64 encoded)
     * @return string Decrypted plain text data
     */
    public function decrypt($encryptedData) {
        if (empty($encryptedData)) {
            return $encryptedData;
        }
        
        // Decode from base64
        $data = base64_decode($encryptedData);
        
        // Extract IV (first 16 bytes for AES-256-CBC)
        $ivLength = openssl_cipher_iv_length($this->cipher);
        $iv = substr($data, 0, $ivLength);
        $encrypted = substr($data, $ivLength);
        
        // Decrypt
        return openssl_decrypt($encrypted, $this->cipher, $this->key, 0, $iv);
    }
    
    /**
     * Encrypt array of PII fields
     * 
     * @param array $data Array with keys to encrypt
     * @param array $fieldsToEncrypt List of field names to encrypt
     * @return array Data with specified fields encrypted
     */
    public function encryptFields($data, $fieldsToEncrypt = ['national_id', 'phone_number', 'email', 'address']) {
        foreach ($fieldsToEncrypt as $field) {
            if (isset($data[$field]) && !empty($data[$field])) {
                $data[$field] = $this->encrypt($data[$field]);
            }
        }
        return $data;
    }
    
    /**
     * Decrypt array of PII fields
     * 
     * @param array $data Array with encrypted fields
     * @param array $fieldsToDecrypt List of field names to decrypt
     * @return array Data with specified fields decrypted
     */
    public function decryptFields($data, $fieldsToDecrypt = ['national_id', 'phone_number', 'email', 'address']) {
        foreach ($fieldsToDecrypt as $field) {
            if (isset($data[$field]) && !empty($data[$field])) {
                $data[$field] = $this->decrypt($data[$field]);
            }
        }
        return $data;
    }
    
    /**
     * Check if data is encrypted (heuristic check)
     * 
     * @param string $data Data to check
     * @return bool True if likely encrypted
     */
    public function isEncrypted($data) {
        if (empty($data)) {
            return false;
        }
        
        // Base64 encoded data is typically longer and has specific character set
        // This is a heuristic check, not foolproof
        return base64_decode($data, true) !== false && 
               strlen($data) > 32 && 
               preg_match('/^[A-Za-z0-9+\/]+=*$/', $data);
    }
}
