<?php
declare(strict_types=1);

/** Encrypt TOTP secrets at rest (libsodium preferred). */
final class AuthCrypto {
    private function __construct() {
    }

    public static function encrypt(string $plain): string {
        if ($plain === '') {
            return '';
        }
        $key = self::key();
        if (function_exists('sodium_crypto_secretbox')) {
            $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
            $cipher = sodium_crypto_secretbox($plain, $nonce, $key);
            return 'sbx:' . base64_encode($nonce . $cipher);
        }
        $iv = random_bytes(16);
        $tag = '';
        $cipher = openssl_encrypt($plain, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag);
        if ($cipher === false) {
            return 'b64:' . base64_encode($plain);
        }
        return 'gcm:' . base64_encode($iv . $tag . $cipher);
    }

    public static function decrypt(string $stored): string {
        if ($stored === '') {
            return '';
        }
        if (str_starts_with($stored, 'sbx:')) {
            $raw = base64_decode(substr($stored, 4), true);
            if ($raw === false || strlen($raw) < SODIUM_CRYPTO_SECRETBOX_NONCEBYTES + SODIUM_CRYPTO_SECRETBOX_MACBYTES) {
                return '';
            }
            $nonce = substr($raw, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
            $cipher = substr($raw, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
            $plain = sodium_crypto_secretbox_open($cipher, $nonce, self::key());
            return $plain === false ? '' : $plain;
        }
        if (str_starts_with($stored, 'gcm:')) {
            $raw = base64_decode(substr($stored, 4), true);
            if ($raw === false || strlen($raw) < 32) {
                return '';
            }
            $iv = substr($raw, 0, 16);
            $tag = substr($raw, 16, 16);
            $cipher = substr($raw, 32);
            $plain = openssl_decrypt($cipher, 'aes-256-gcm', self::key(), OPENSSL_RAW_DATA, $iv, $tag);
            return is_string($plain) ? $plain : '';
        }
        if (str_starts_with($stored, 'b64:')) {
            $v = base64_decode(substr($stored, 4), true);
            return is_string($v) ? $v : '';
        }
        return '';
    }

    /** @return string 32-byte key */
    private static function key(): string {
        $pepper = (string) cfg('auth.encryption_key', '');
        if ($pepper === '') {
            $pepper = 'dev-change-me-set-auth.encryption_key-in-config.php';
        }
        return hash('sha256', $pepper, true);
    }
}
