<?php

declare(strict_types=1);

namespace CpCreation\VitiCore\Marketing\Emailing;

final readonly class BrevoSecretCipher
{
    private const string CIPHER = 'aes-256-gcm';
    private const string VERSION = 'v1';
    private const int NONCE_LENGTH = 12;
    private const int TAG_LENGTH = 16;

    public function __construct(
        #[\SensitiveParameter]
        private string $appSecret,
    ) {}

    public function encrypt(#[\SensitiveParameter] string $apiKey): string
    {
        if ('' === mb_trim($apiKey)) {
            throw new \InvalidArgumentException('La clé API Brevo ne peut pas être vide.');
        }

        $nonce = random_bytes(self::NONCE_LENGTH);
        $tag = '';
        $encrypted = openssl_encrypt(
            $apiKey,
            self::CIPHER,
            $this->key(),
            \OPENSSL_RAW_DATA,
            $nonce,
            $tag,
            'viticore-emailing:brevo-api-key',
            self::TAG_LENGTH,
        );
        if (false === $encrypted) {
            throw new \RuntimeException('La clé API Brevo n’a pas pu être chiffrée.');
        }

        return implode('.', [
            self::VERSION,
            self::encode($nonce),
            self::encode($encrypted),
            self::encode($tag),
        ]);
    }

    public function decrypt(#[\SensitiveParameter] string $envelope): string
    {
        $parts = explode('.', $envelope);
        if (4 !== \count($parts) || self::VERSION !== $parts[0]) {
            throw new \RuntimeException('La clé API Brevo enregistrée est illisible.');
        }

        $value = openssl_decrypt(
            self::decode($parts[2]),
            self::CIPHER,
            $this->key(),
            \OPENSSL_RAW_DATA,
            self::decode($parts[1]),
            self::decode($parts[3]),
            'viticore-emailing:brevo-api-key',
        );
        if (false === $value || '' === $value) {
            throw new \RuntimeException('La clé API Brevo enregistrée est illisible.');
        }

        return $value;
    }

    private function key(): string
    {
        if ('' === mb_trim($this->appSecret)) {
            throw new \LogicException('APP_SECRET doit être configuré pour protéger la clé API Brevo.');
        }

        return hash_hkdf('sha256', $this->appSecret, 32, 'viticore-emailing-secrets-v1');
    }

    private static function encode(string $value): string
    {
        return mb_rtrim(strtr(base64_encode($value), '+/', '-_'), '=');
    }

    private static function decode(string $value): string
    {
        if ('' === $value || 1 !== preg_match('/^[A-Za-z0-9_-]+$/D', $value)) {
            throw new \RuntimeException('La clé API Brevo enregistrée est illisible.');
        }

        $decoded = base64_decode(
            strtr($value, '-_', '+/') . str_repeat('=', (4 - mb_strlen($value, '8bit') % 4) % 4),
            true,
        );
        if (false === $decoded || self::encode($decoded) !== $value) {
            throw new \RuntimeException('La clé API Brevo enregistrée est illisible.');
        }

        return $decoded;
    }
}
