<?php
/**
 * HVAC Secure Storage - Encrypted credential storage
 *
 * @package HVAC_Community_Events
 * @since 1.0.7
 */

if (!defined('ABSPATH')) {
    exit;
}

/**
 * HVAC_Secure_Storage class
 * 
 * Provides encrypted storage for sensitive data like API keys
 */
class HVAC_Secure_Storage {
    
    /**
     * Encryption method
     */
    const ENCRYPTION_METHOD = 'AES-256-CBC';
    
    /**
     * Get encryption key
     *
     * SECURITY FIX (C2): Prefer wp-config.php constant over database storage.
     * Storing encryption key in the same database as encrypted data is "key under doormat".
     * Define HVAC_ENCRYPTION_KEY in wp-config.php for proper key separation.
     *
     * @return string
     */
    private static function get_encryption_key() {
        // Prefer wp-config.php constant (recommended for production)
        if (defined('HVAC_ENCRYPTION_KEY') && HVAC_ENCRYPTION_KEY) {
            return base64_decode(HVAC_ENCRYPTION_KEY);
        }

        // Fallback to database storage (legacy/development)
        // Log warning in debug mode to encourage migration
        if (WP_DEBUG) {
            error_log('HVAC Security Warning: HVAC_ENCRYPTION_KEY not defined in wp-config.php. Using database-stored key (less secure).');
        }

        $key = get_option('hvac_encryption_key');

        if (!$key) {
            // Generate a new key if one doesn't exist
            $key = base64_encode(random_bytes(32));
            update_option('hvac_encryption_key', $key);
        }

        return base64_decode($key);
    }
    
    /**
     * Encrypt data
     * 
     * @param string $data Data to encrypt
     * @return string Encrypted data
     */
    public static function encrypt($data) {
        if (empty($data)) {
            return '';
        }
        
        $key = self::get_encryption_key();
        $iv = random_bytes(openssl_cipher_iv_length(self::ENCRYPTION_METHOD));
        
        $encrypted = openssl_encrypt($data, self::ENCRYPTION_METHOD, $key, 0, $iv);
        
        if ($encrypted === false) {
            return false;
        }
        
        return base64_encode($iv . $encrypted);
    }
    
    /**
     * Decrypt data
     * 
     * @param string $encrypted_data Encrypted data
     * @return string|false Decrypted data or false on failure
     */
    public static function decrypt($encrypted_data) {
        if (empty($encrypted_data)) {
            return '';
        }
        
        $data = base64_decode($encrypted_data);
        if ($data === false) {
            return false;
        }
        
        $key = self::get_encryption_key();
        $iv_length = openssl_cipher_iv_length(self::ENCRYPTION_METHOD);
        
        if (strlen($data) < $iv_length) {
            return false;
        }
        
        $iv = substr($data, 0, $iv_length);
        $encrypted = substr($data, $iv_length);
        
        return openssl_decrypt($encrypted, self::ENCRYPTION_METHOD, $key, 0, $iv);
    }
    
    /**
     * Store encrypted credential
     * 
     * @param string $option_name Option name
     * @param string $value Value to store
     * @return bool Success
     */
    public static function store_credential($option_name, $value) {
        if (empty($value)) {
            delete_option($option_name);
            return true;
        }
        
        $encrypted = self::encrypt($value);
        if ($encrypted === false) {
            return false;
        }
        
        return update_option($option_name, $encrypted);
    }
    
    /**
     * Retrieve encrypted credential
     * 
     * @param string $option_name Option name
     * @param string $default Default value
     * @return string Decrypted value
     */
    public static function get_credential($option_name, $default = '') {
        $encrypted = get_option($option_name, '');
        
        if (empty($encrypted)) {
            return $default;
        }
        
        $decrypted = self::decrypt($encrypted);
        return $decrypted !== false ? $decrypted : $default;
    }
    
    /**
     * Migrate existing plaintext credentials to encrypted storage
     * 
     * @return array Migration results
     */
    public static function migrate_existing_credentials() {
        $credentials_to_migrate = [
            'hvac_zoho_client_id',
            'hvac_zoho_client_secret',
            'hvac_zoho_refresh_token',
            'hvac_google_maps_api_key'
        ];
        
        $results = [
            'migrated' => 0,
            'skipped' => 0,
            'errors' => []
        ];
        
        foreach ($credentials_to_migrate as $option_name) {
            $plaintext = get_option($option_name, '');
            
            if (empty($plaintext)) {
                $results['skipped']++;
                continue;
            }
            
            // Check if it's already encrypted (basic heuristic)
            $decrypted = self::decrypt($plaintext);
            if ($decrypted !== false && $decrypted !== $plaintext) {
                $results['skipped']++;
                continue;
            }
            
            // Migrate to encrypted storage
            if (self::store_credential($option_name, $plaintext)) {
                $results['migrated']++;
            } else {
                $results['errors'][] = "Failed to migrate: $option_name";
            }
        }
        
        return $results;
    }
    
    /**
     * Check if OpenSSL is available
     * 
     * @return bool
     */
    public static function is_encryption_available() {
        return function_exists('openssl_encrypt') && function_exists('openssl_decrypt');
    }
}