<?php
declare(strict_types=1);
namespace WPUltimateSecurity\UltimateSecurity\Support\Helpers;

class ApiKeyCryptoService
{
    private const KEYS = [
        'security' => [
            're_captcha' => [
                'site_key',
                'secret_key',
            ],
            'cloudflare_turnstile' => [
                'site_key',
                'secret_key',
            ],
            'email_notification' => [
                'slack_webhook'
            ]
        ],
        'audit_files' => [
            'google_api_key',
            'openrouter_api_key',
            'openai_api_key',
            'requesty_api_key',
        ],
        'vulnerability_scanner' => [
            'wpscan_api_key',
            'patchstack_api_key',
        ],
        '2fa_authentication' => [
            'sms_authentication' => [
                'twilio_account_sid',
                'twilio_auth_token',
                'twilio_from_number',
            ],
        ],
        // REMOVED: restrictions.maxmind - server-level feature
    ];

    /**
     * Decrypt API keys in the options array.
     * Safely handles both encrypted and plaintext data.
     *
     * @param array $output Options array to decrypt
     * @return array Options with decrypted API keys
     */
    public static function decrypt(array $output): array
    {
        self::processKeys($output, self::KEYS, 'decrypt');
        return $output;
    }

    /**
     * Encrypt API keys in the options array.
     * Skips already encrypted data to prevent double encryption.
     *
     * @param array $output Options array to encrypt
     * @return array Options with encrypted API keys
     */
    public static function encrypt(array $output): array
    {
        self::processKeys($output, self::KEYS, 'encrypt');
        return $output;
    }

    /**
     * Recursive processor for encrypt/decrypt operations
     *
     * @param array  $data   Data to process (by reference)
     * @param array  $keys   Keys map to process
     * @param string $method Either 'encrypt' or 'decrypt'
     */
    private static function processKeys(
        array &$data,
        array $keys,
        string $method
    ): void {
        foreach ($keys as $key => $value) {

            // Leaf level (actual secret keys)
            if (is_array($value) && array_is_list($value)) {
                foreach ($value as $field) {
                    if (!empty($data[$key][$field]) && is_string($data[$key][$field])) {
                        $data[$key][$field] = self::processValue(
                            $data[$key][$field],
                            $method
                        );
                    }
                }
                continue;
            }

            // Nested structure
            if (
                is_array($value) &&
                isset($data[$key]) &&
                is_array($data[$key])
            ) {
                self::processKeys($data[$key], $value, $method);
            }
        }
    }

    /**
     * Process a single value for encrypt/decrypt
     *
     * @param string $value  The value to process
     * @param string $method Either 'encrypt' or 'decrypt'
     * @return string The processed value
     */
    private static function processValue(string $value, string $method): string
    {
        if ($method === 'decrypt') {
            // Only decrypt if the value appears to be encrypted
            if (CryptoHelper::isEncrypted($value)) {
                $decrypted = CryptoHelper::decrypt($value);
                // If decryption fails, return original value (might be plaintext)
                return $decrypted !== false ? $decrypted : $value;
            }
            // Value is not encrypted, return as-is
            return $value;
        }

        if ($method === 'encrypt') {
            // Don't double-encrypt already encrypted values
            if (CryptoHelper::isEncrypted($value)) {
                return $value;
            }
            // Encrypt the plaintext value
            $encrypted = CryptoHelper::encrypt($value);
            return $encrypted !== false ? $encrypted : $value;
        }

        return $value;
    }
}
// Before Save
// $input = ApiKeyCryptoService::encrypt($input);
// Before Output
// $output = ApiKeyCryptoService::decrypt($output);