<?php
/**
 * Server-side encryption handler for securing chat data
 *
 * This class provides server-side encryption/decryption capabilities
 * to work with client-side encrypted data.
 *
 * @package Askany
 * @since 1.0.0
 */

namespace Askany;

/**
 * Encryption Handler class for server-side encryption operations
 *
 * @package Askany
 * @since 1.0.0
 */
class EncryptionHandler {
    
    /**
     * Check if data appears to be encrypted (base64 encoded)
     *
     * @param string $data The data to check
     * @return bool True if data appears encrypted
     */
    public static function is_encrypted_data($data) {
        if (empty($data) || !is_string($data)) {
            return false;
        }
        
        // Check if it's base64 encoded (basic check)
        return base64_encode(base64_decode($data, true)) === $data;
    }
    
    /**
     * Check if data is base64 encoded (for simple encoding/decoding)
     *
     * @param string $data The data to check
     * @return bool True if data is base64 encoded
     */
    public static function is_base64_encoded($data) {
        if (empty($data) || !is_string($data)) {
            return false;
        }
        
        // Check if it's valid base64 and not just random text
        if (!preg_match('/^[A-Za-z0-9+\/]*={0,2}$/', $data)) {
            return false;
        }
        
        $decoded = base64_decode($data, true);
        return $decoded !== false && base64_encode($decoded) === $data;
    }
    
    /**
     * Decode base64 encoded message
     *
     * @param string $encoded_data The base64 encoded data
     * @return string The decoded message
     */
    public static function decode_base64_message($encoded_data) {
        try {
            if (empty($encoded_data)) {
                return $encoded_data;
            }
            
            $decoded = base64_decode($encoded_data, true);
            if ($decoded === false) {
                return $encoded_data; // Return original if decoding fails
            }
            
            // Decode URL encoding if present
            $final_decoded = urldecode($decoded);
            
            return $final_decoded;
        } catch (Exception $e) {
            self::log_encryption_event('DECODE_ERROR', 'Failed to decode base64 message', array(
                'error' => $e->getMessage(),
                'data_length' => strlen($encoded_data)
            ));
            return $encoded_data;
        }
    }
    
    /**
     * Deobfuscate data received from client
     *
     * @param string $obfuscated_data The obfuscated data
     * @return string The deobfuscated data
     */
    public static function deobfuscate_data($obfuscated_data) {
        try {
            if (empty($obfuscated_data)) {
                return $obfuscated_data;
            }
            
            $decoded = base64_decode($obfuscated_data);
            if ($decoded === false) {
                return $obfuscated_data;
            }
            
            $parts = explode('|', $decoded);
            if (count($parts) === 3) {
                return $parts[1]; // Return the middle part (actual encrypted data)
            }
            
            return $obfuscated_data;
        } catch (Exception $e) {
            // error_log('Deobfuscation error: ' . $e->getMessage());
            return $obfuscated_data;
        }
    }
    
    /**
     * Obfuscate data for client transmission
     *
     * @param string $encrypted_data The encrypted data
     * @return string The obfuscated data
     */
    public static function obfuscate_data($encrypted_data) {
        try {
            if (empty($encrypted_data)) {
                return $encrypted_data;
            }
            
            // Add random padding and encode
            $padding = substr(md5(uniqid(rand(), true)), 0, 15);
            $combined = $padding . '|' . $encrypted_data . '|' . strrev($padding);
            return base64_encode($combined);
        } catch (Exception $e) {
            // error_log('Obfuscation error: ' . $e->getMessage());
            return $encrypted_data;
        }
    }
    
    /**
     * Process encrypted request data
     *
     * @param array $request_data The request data
     * @return array Processed request data
     */
    public static function process_encrypted_request($request_data) {
        $processed = $request_data;
        
        // Check if encryption flag is set
        $is_encrypted = isset($request_data['encrypted']) && $request_data['encrypted'];
        
        if ($is_encrypted) {
            // Handle message/query field - decode base64 encoded data
            if (isset($request_data['message']) && self::is_base64_encoded($request_data['message'])) {
                // Decode base64 encoded message for storage
                $decoded = self::decode_base64_message($request_data['message']);
                $processed['message'] = $decoded;
                $processed['_original_message_encrypted'] = true;
                
                self::log_encryption_event('DECODE_MESSAGE', 'Decoded base64 message data', array(
                    'original_length' => strlen($request_data['message']),
                    'decoded_length' => strlen($decoded)
                ));
            } elseif (isset($request_data['query']) && self::is_base64_encoded($request_data['query'])) {
                // Decode base64 encoded query (REST API)
                $decoded = self::decode_base64_message($request_data['query']);
                $processed['query'] = $decoded;
                $processed['_original_query_encrypted'] = true;
                
                self::log_encryption_event('DECODE_QUERY', 'Decoded base64 query data', array(
                    'original_length' => strlen($request_data['query']),
                    'decoded_length' => strlen($decoded)
                ));
            }
            
            // Handle session ID
            if (isset($request_data['session_id']) && self::is_base64_encoded($request_data['session_id'])) {
                // Decode base64 encoded session ID
                $decoded = self::decode_base64_message($request_data['session_id']);
                $processed['session_id'] = $decoded;
                $processed['_original_session_encrypted'] = true;
                
                self::log_encryption_event('DECODE_SESSION', 'Decoded base64 session ID', array(
                    'original_length' => strlen($request_data['session_id']),
                    'decoded_length' => strlen($decoded)
                ));
            }
        }
        
        return $processed;
    }
    
    /**
     * Process response data for encryption
     *
     * @param array $response_data The response data
     * @param array $request_data The original request data
     * @return array Processed response data
     */
    public static function process_encrypted_response($response_data, $request_data = array()) {
        $processed = $response_data;
        
        // Check if original request was encrypted
        $should_encrypt = isset($request_data['encrypted']) && $request_data['encrypted'];
        
        if ($should_encrypt) {
            $processed['encrypted'] = true;
            
            // Obfuscate response fields (client will handle actual encryption/decryption)
            if (isset($response_data['message'])) {
                $processed['message'] = self::obfuscate_data($response_data['message']);
            }
            
            if (isset($response_data['session_id'])) {
                $processed['session_id'] = self::obfuscate_data($response_data['session_id']);
            }
            
            if (isset($response_data['related_products'])) {
                $products_json = json_encode($response_data['related_products']);
                $processed['related_products'] = self::obfuscate_data($products_json);
            }
        }
        
        return $processed;
    }
    
    /**
     * Sanitize and validate encrypted data
     *
     * @param string $data The data to sanitize
     * @return string Sanitized data
     */
    public static function sanitize_encrypted_data($data) {
        if (empty($data)) {
            return $data;
        }
        
        // For encrypted data, we only do basic sanitization
        // since the actual content is encrypted
        return sanitize_text_field($data);
    }
    
    /**
     * Log encryption-related events for debugging
     *
     * @param string $event The event type
     * @param string $message The log message
     * @param array $context Additional context
     */
    public static function log_encryption_event($event, $message, $context = array()) {
        if (defined('WP_DEBUG') && WP_DEBUG) {
            $log_message = sprintf(
                '[AskAny Encryption] %s: %s',
                $event,
                $message
            );
            
            if (!empty($context)) {
                $log_message .= ' Context: ' . json_encode($context);
            }
            
            // error_log($log_message);
        }
    }
    
    /**
     * Generate a secure hash for data integrity verification
     *
     * @param string $data The data to hash
     * @return string The hash
     */
    public static function generate_data_hash($data) {
        return hash('sha256', $data . wp_salt('nonce'));
    }
    
    /**
     * Verify data integrity using hash
     *
     * @param string $data The data to verify
     * @param string $expected_hash The expected hash
     * @return bool True if hash matches
     */
    public static function verify_data_hash($data, $expected_hash) {
        $actual_hash = self::generate_data_hash($data);
        return hash_equals($expected_hash, $actual_hash);
    }
}