<?php
/**
 * Security Helper
 *
 * @package Licenzo\Helper
 */

namespace Licenzo\Helper;

// Prevent direct access
if (!defined('ABSPATH')) {
    exit;
}

/**
 * Security utilities for data sanitization and validation
 */
class Security
{
    /**
     * Sanitize text field
     *
     * @param string $text
     * @return string
     */
    public static function sanitizeText($text)
    {
        return sanitize_text_field($text);
    }

    /**
     * Sanitize textarea field
     *
     * @param string $text
     * @return string
     */
    public static function sanitizeTextarea($text)
    {
        return sanitize_textarea_field($text);
    }

    /**
     * Sanitize email
     *
     * @param string $email
     * @return string
     */
    public static function sanitizeEmail($email)
    {
        return sanitize_email($email);
    }

    /**
     * Sanitize URL
     *
     * @param string $url
     * @return string
     */
    public static function sanitizeUrl($url)
    {
        return esc_url_raw($url);
    }

    /**
     * Sanitize integer
     *
     * @param mixed $value
     * @return int
     */
    public static function sanitizeInt($value)
    {
        return intval($value);
    }

    /**
     * Sanitize float
     *
     * @param mixed $value
     * @return float
     */
    public static function sanitizeFloat($value)
    {
        return floatval($value);
    }

    /**
     * Sanitize boolean
     *
     * @param mixed $value
     * @return bool
     */
    public static function sanitizeBool($value)
    {
        return (bool) $value;
    }

    /**
     * Sanitize array of strings
     *
     * @param array $array
     * @return array
     */
    public static function sanitizeArray($array)
    {
        if (!is_array($array)) {
            return [];
        }

        return array_map([static::class, 'sanitizeText'], $array);
    }

    /**
     * Escape HTML for output
     *
     * @param string $text
     * @return string
     */
    public static function escapeHtml($text)
    {
        return esc_html($text);
    }

    /**
     * Escape HTML attributes
     *
     * @param string $text
     * @return string
     */
    public static function escapeAttr($text)
    {
        return esc_attr($text);
    }

    /**
     * Escape JavaScript
     *
     * @param string $text
     * @return string
     */
    public static function escapeJs($text)
    {
        return esc_js($text);
    }

    /**
     * Mask API key for display (show only first and last few characters)
     *
     * @param string $apiKey
     * @param int $showChars Number of characters to show at start and end
     * @return string
     */
    public static function maskApiKey($apiKey, $showChars = 4)
    {
        if (empty($apiKey) || strlen($apiKey) <= $showChars * 2) {
            return str_repeat('*', 8);
        }

        $start = substr($apiKey, 0, $showChars);
        $end = substr($apiKey, -$showChars);
        $middle = str_repeat('*', max(8, strlen($apiKey) - $showChars * 2));

        return $start . $middle . $end;
    }

    /**
     * Hash API key for storage (one-way hash for comparison)
     *
     * @param string $apiKey
     * @return string
     */
    public static function hashApiKey($apiKey)
    {
        return wp_hash($apiKey);
    }

    private const CIPHER = 'AES-256-CBC';
    private const IV_LENGTH = 16;
    private const MAC_LENGTH = 32;
    private const HKDF_INFO_ENCRYPT = 'licenzo-encrypt';
    private const HKDF_INFO_MAC = 'licenzo-mac';

    /**
     * Encrypt sensitive data with Encrypt-then-MAC.
     *
     * @param string $data
     * @return string base64(iv . ciphertext . mac)
     */
    public static function encrypt($data)
    {
        if (!function_exists('wp_salt')) {
            throw new \RuntimeException('Encryption requires WordPress wp_salt() function.');
        }

        $rawKey = wp_salt('auth');
        $encKey = hash_hkdf('sha256', $rawKey, 32, static::HKDF_INFO_ENCRYPT);
        $macKey = hash_hkdf('sha256', $rawKey, 32, static::HKDF_INFO_MAC);

        $iv = openssl_random_pseudo_bytes(static::IV_LENGTH);
        $ciphertext = openssl_encrypt($data, static::CIPHER, $encKey, OPENSSL_RAW_DATA, $iv);

        if ($ciphertext === false) {
            throw new \RuntimeException('Encryption failed.');
        }

        $mac = hash_hmac('sha256', $iv . $ciphertext, $macKey, true);

        return base64_encode($iv . $ciphertext . $mac);
    }

    /**
     * Decrypt sensitive data with MAC verification.
     *
     * @param string $encryptedData
     * @return string|false
     */
    public static function decrypt($encryptedData)
    {
        if (!function_exists('wp_salt')) {
            throw new \RuntimeException('Decryption requires WordPress wp_salt() function.');
        }

        $rawKey = wp_salt('auth');
        $encKey = hash_hkdf('sha256', $rawKey, 32, static::HKDF_INFO_ENCRYPT);
        $macKey = hash_hkdf('sha256', $rawKey, 32, static::HKDF_INFO_MAC);

        $decoded = base64_decode($encryptedData, true);
        $minLength = static::IV_LENGTH + 1 + static::MAC_LENGTH;
        if ($decoded === false || strlen($decoded) < $minLength) {
            return false;
        }

        $mac = substr($decoded, -static::MAC_LENGTH);
        $ivAndCiphertext = substr($decoded, 0, -static::MAC_LENGTH);

        $expectedMac = hash_hmac('sha256', $ivAndCiphertext, $macKey, true);
        if (!hash_equals($expectedMac, $mac)) {
            return false;
        }

        $iv = substr($ivAndCiphertext, 0, static::IV_LENGTH);
        $ciphertext = substr($ivAndCiphertext, static::IV_LENGTH);

        return openssl_decrypt($ciphertext, static::CIPHER, $encKey, OPENSSL_RAW_DATA, $iv);
    }

    /**
     * Verify nonce for AJAX requests
     *
     * @param string $nonce
     * @param string $action
     * @return bool
     */
    public static function verifyNonce($nonce, $action = 'LICENZO_nonce')
    {
        return wp_verify_nonce($nonce, $action);
    }

    /**
     * Check if current user has required capability
     *
     * @param string $capability
     * @return bool
     */
    public static function currentUserCan($capability = 'manage_options')
    {
        return current_user_can($capability);
    }

    /**
     * Sanitize and validate JSON data
     *
     * @param string $json
     * @return array|null
     */
    public static function sanitizeJson($json)
    {
        $data = json_decode($json, true);

        if (json_last_error() !== JSON_ERROR_NONE) {
            return null;
        }

        return $data;
    }

    /**
     * Rate limiting check (simple implementation)
     *
     * @param string $key Unique identifier for the rate limit
     * @param int $limit Number of requests allowed
     * @param int $window Time window in seconds
     * @return bool True if within limits, false if exceeded
     */
    public static function checkRateLimit($key, $limit = 60, $window = 3600)
    {
        $transient_key = 'licenzo_rate_limit_' . md5($key);
        $requests = get_transient($transient_key);

        if ($requests === false) {
            set_transient($transient_key, 1, $window);
            return true;
        }

        if ($requests >= $limit) {
            return false;
        }

        set_transient($transient_key, $requests + 1, $window);
        return true;
    }
}
