<?php

namespace WPSN\Modules\Licensing;

defined('ABSPATH') || exit;

/**
 * Best-effort encryption for sensitive cached payloads.
 *
 * This is not a silver bullet (PHP code is GPL), but it:
 * - avoids plain-text license payloads in wp_options,
 * - ties cache data to WP salts.
 */
final class LicenseCrypto
{
    private const PREFIX_ENC = 'enc:';
    private const PREFIX_PLAIN = 'plain:';

    /**
     * Derive an encryption key from WP salts.
     */
    private static function key(): string
    {
        // wp_salt() is available since forever; fallback to AUTH_KEY.
        $salt = function_exists('wp_salt') ? (string) wp_salt('auth') : (defined('AUTH_KEY') ? (string) AUTH_KEY : '');
        if ($salt === '') {
            $salt = 'wpsn-fallback-salt';
        }
        // 32 bytes key.
        return hash('sha256', $salt, true);
    }

    /**
     * @return string encrypted payload
     */
    public static function encrypt(string $plain): string
    {
        $plain = (string) $plain;
        if ($plain === '') {
            return '';
        }

        if (function_exists('openssl_encrypt')) {
            $key = self::key();
            $iv = substr(hash('sha256', $key . 'iv', true), 0, 16);

            $enc = openssl_encrypt($plain, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
            if (is_string($enc) && $enc !== '') {
                return self::PREFIX_ENC . base64_encode($enc);
            }
        }

        return self::PREFIX_PLAIN . base64_encode($plain);
    }

    /**
     * @return string decrypted payload or empty string
     */
    public static function decrypt(string $cipher): string
    {
        $cipher = (string) $cipher;
        if ($cipher === '') {
            return '';
        }

        if (strpos($cipher, self::PREFIX_ENC) === 0) {
            $b64 = substr($cipher, strlen(self::PREFIX_ENC));
            $raw = base64_decode($b64, true);
            if (!is_string($raw) || $raw === '') {
                return '';
            }

            if (function_exists('openssl_decrypt')) {
                $key = self::key();
                $iv = substr(hash('sha256', $key . 'iv', true), 0, 16);

                $plain = openssl_decrypt($raw, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
                return is_string($plain) ? $plain : '';
            }

            return '';
        }

        if (strpos($cipher, self::PREFIX_PLAIN) === 0) {
            $b64 = substr($cipher, strlen(self::PREFIX_PLAIN));
            $plain = base64_decode($b64, true);
            return is_string($plain) ? $plain : '';
        }

        // Back-compat: treat as base64 plain.
        $plain = base64_decode($cipher, true);
        return is_string($plain) ? $plain : '';
    }
}
