<?php
/**
 * Handles encryption and decryption of sensitive data
 */

// If this file is called directly, abort.
if (!defined('ABSPATH')) {
    exit;
}

class Mementor_TTS_Encryption {
    private $key;
    private $salt;
    private $debug_mode;

    public function __construct() {
        // Use WordPress' authentication keys from wp-config.php
        $this->key = defined('AUTH_KEY') ? AUTH_KEY : '';
        $this->salt = defined('SECURE_AUTH_SALT') ? SECURE_AUTH_SALT : '';
        $this->debug_mode = get_option('mementor_tts_debug_mode', '0') === '1';

        // If WordPress keys are not available, generate fallback keys
        if (empty($this->key) || empty($this->salt)) {
            $this->log_error('AUTH_KEY or SECURE_AUTH_SALT not defined in wp-config.php, using fallback keys');
            
            // Generate a site-specific key using the site URL and database prefix
            global $wpdb;
            $site_url = get_site_url();
            $db_prefix = $wpdb->prefix;
            
            // Create deterministic but unique keys for this site
            $this->key = hash('sha256', $site_url . $db_prefix . 'mementor_tts_key');
            $this->salt = hash('sha256', $site_url . $db_prefix . 'mementor_tts_salt');
            
            $this->log_error('Generated fallback keys based on site configuration');
        }
    }

    /**
     * Show admin notice for missing authentication keys
     */
    public function show_keys_missing_notice() {
        if (current_user_can('manage_options')) {
            ?>
            <div class="notice notice-error is-dismissible">
                <p><?php esc_html_e('Mementor Text to Speech: Authentication keys are not properly configured in wp-config.php. This may affect the security of stored API keys.', 'text-to-speech-tts'); ?></p>
            </div>
            <?php
        }
    }

    public function encrypt($value) {
        if (!extension_loaded('openssl')) {
            $this->log_error('OpenSSL extension not loaded - encryption not possible');
            add_action('admin_notices', array($this, 'show_openssl_missing_notice'));
            return false; // Never return unencrypted data
        }

        $method = 'aes-256-ctr';
        $ivlen  = openssl_cipher_iv_length($method);
        $iv     = random_bytes($ivlen);

        $raw_value = openssl_encrypt($value . $this->salt, $method, $this->key, 0, $iv);
        if (!$raw_value) {
            $this->log_error('Encryption failed: ' . openssl_error_string());
            return false;
        }

        return base64_encode($iv . $raw_value);
    }

    public function decrypt($raw_value) {
        if (!extension_loaded('openssl')) {
            $this->log_error('OpenSSL extension not loaded - decryption not possible');
            add_action('admin_notices', array($this, 'show_openssl_missing_notice'));
            return false; // Never return potentially unencrypted data
        }

        // If the raw value is empty, return false
        if (empty($raw_value)) {
            $this->log_error('Empty value provided for decryption');
            return false;
        }

        // Never return unencrypted values - this is a security risk
        // If we can't decrypt, return false

        // Try to base64 decode the value
        $decoded_value = base64_decode($raw_value, true);
        if ($decoded_value === false) {
            $this->log_error('Failed to base64 decode the encrypted value');
            return false;
        }

        $method = 'aes-256-ctr';
        
        // Check if the method is supported
        if (!in_array($method, openssl_get_cipher_methods())) {
            $this->log_error('Encryption method ' . $method . ' not supported');
            return false;
        }
        
        $ivlen = openssl_cipher_iv_length($method);
        
        // Check if the decoded value is long enough to contain the IV
        if (strlen($decoded_value) <= $ivlen) {
            $this->log_error('Decoded value too short to contain IV');
            return false;
        }
        
        $iv = substr($decoded_value, 0, $ivlen);
        $raw_value = substr($decoded_value, $ivlen);

        try {
            $value = openssl_decrypt($raw_value, $method, $this->key, 0, $iv);
            
            // Check if decryption failed
            if ($value === false) {
                $this->log_error('OpenSSL decrypt failed: ' . openssl_error_string());
                return false;
            }
            
            // Check if the salt is present at the end of the decrypted value
            if (substr($value, - strlen($this->salt)) !== $this->salt) {
                $this->log_error('Salt verification failed during decryption');
                return false;
            }
            
            $decrypted = substr($value, 0, - strlen($this->salt));
            // Success - no need to log
            return $decrypted;
        } catch (Exception $e) {
            $this->log_error('Exception during decryption: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * Show admin notice for missing OpenSSL extension
     */
    public function show_openssl_missing_notice() {
        if (current_user_can('manage_options')) {
            ?>
            <div class="notice notice-error is-dismissible">
                <p><?php esc_html_e('Mementor Text to Speech: The OpenSSL PHP extension is required for secure encryption but is not installed. Please contact your hosting provider.', 'text-to-speech-tts'); ?></p>
            </div>
            <?php
        }
    }

    /**
     * Log errors based on debug mode
     *
     * @param string $message The message to log
     * @param string $type The notice type (error, warning, info)
     */
    private function log_error($message, $type = 'error') {
        // Only log if WordPress debug mode is enabled
        if (defined('WP_DEBUG') && WP_DEBUG) {
            // Log to debug.log if enabled
            if (defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) {
                if (function_exists('wp_debug_log')) {
                    wp_debug_log('[Mementor TTS Encryption] ' . $message);
                }
            }
            
            // Show admin notice for errors and warnings
            if ($type === 'error' || $type === 'warning') {
                $this->add_admin_notice($message, $type);
            }
        }
    }

    /**
     * Add an admin notice
     *
     * @param string $message The notice message
     * @param string $type The notice type (error, warning, success, info)
     */
    private function add_admin_notice($message, $type = 'error') {
        add_action('admin_notices', function() use ($message, $type) {
            if (current_user_can('manage_options')) {
                printf(
                    '<div class="notice notice-%s is-dismissible"><p>%s</p></div>',
                    esc_attr($type),
                    esc_html($message)
                );
            }
        });
    }
}
