<?php

namespace classes;

use RuntimeException;

class replication_secret_box
{
    private const PREFIX = 'twsec:v1:';
    private const CIPHER = 'aes-256-gcm';

    public static function encrypt(string $plaintext): string
    {
        $nonce = random_bytes(12);
        $tag = '';
        $ciphertext = openssl_encrypt(
            $plaintext,
            self::CIPHER,
            self::key(),
            OPENSSL_RAW_DATA,
            $nonce,
            $tag,
            '',
            16
        );

        if ($ciphertext === false || $tag === '') {
            throw new RuntimeException('Secret encryption failed.');
        }

        return self::PREFIX . base64_encode(json_encode([
            'nonce' => base64_encode($nonce),
            'tag' => base64_encode($tag),
            'ciphertext' => base64_encode($ciphertext),
        ], JSON_UNESCAPED_SLASHES));
    }

    public static function decrypt(?string $secret): string
    {
        $secret = (string)$secret;
        if ($secret === '') {
            return '';
        }

        if (!str_starts_with($secret, self::PREFIX)) {
            return $secret;
        }

        $payload = json_decode(base64_decode(substr($secret, strlen(self::PREFIX)), true) ?: '', true);
        if (!is_array($payload)) {
            throw new RuntimeException('Encrypted secret payload is invalid.');
        }

        $nonce = base64_decode((string)($payload['nonce'] ?? ''), true);
        $tag = base64_decode((string)($payload['tag'] ?? ''), true);
        $ciphertext = base64_decode((string)($payload['ciphertext'] ?? ''), true);

        if ($nonce === false || $tag === false || $ciphertext === false) {
            throw new RuntimeException('Encrypted secret payload is incomplete.');
        }

        $plaintext = openssl_decrypt(
            $ciphertext,
            self::CIPHER,
            self::key(),
            OPENSSL_RAW_DATA,
            $nonce,
            $tag
        );

        if ($plaintext === false) {
            throw new RuntimeException('Secret decryption failed.');
        }

        return $plaintext;
    }

    public static function mask(?string $value): string
    {
        $value = (string)$value;
        if ($value === '') {
            return '';
        }

        $length = strlen($value);
        if ($length <= 4) {
            return str_repeat('*', $length);
        }

        return substr($value, 0, 2) . str_repeat('*', max(4, $length - 4)) . substr($value, -2);
    }

    private static function key(): string
    {
        $keyMaterial = (string)($GLOBALS['ENCRYPTION_KEY'] ?? getenv('ENCRYPTION_KEY') ?: '');
        if (trim($keyMaterial) === '') {
            throw new RuntimeException('ENCRYPTION_KEY is required for replication secret encryption.');
        }

        return hash('sha256', $keyMaterial, true);
    }
}
