<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\DocStoreBundle\Service\Signature\Driver\BaseSigner;

use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Exception\MessageDecodingFailedException;
use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface;

/**
 * Decode (and requeue) @see{PdfSignedMessage}, which comes from an external producer.
 */
final readonly class PdfSignedMessageSerializer implements SerializerInterface
{
    public function decode(array $encodedEnvelope): Envelope
    {
        $body = $encodedEnvelope['body'];

        try {
            $decoded = json_decode((string) $body, true, 512, JSON_THROW_ON_ERROR);
        } catch (\JsonException $e) {
            throw new MessageDecodingFailedException('Could not deserialize message', previous: $e);
        }

        if (!array_key_exists('signatureId', $decoded) || !array_key_exists('content', $decoded)) {
            throw new MessageDecodingFailedException('Could not find expected keys: signatureId or content');
        }

        $content = base64_decode((string) $decoded['content'], true);

        if (false === $content) {
            throw new MessageDecodingFailedException('Invalid character found in the base64 encoded content');
        }

        $message = new PdfSignedMessage($decoded['signatureId'], $decoded['signatureZoneIndex'], $content);

        return new Envelope($message);
    }

    public function encode(Envelope $envelope): array
    {
        $message = $envelope->getMessage();

        if (!$message instanceof PdfSignedMessage) {
            throw new MessageDecodingFailedException('Expected a PdfSignedMessage');
        }

        $data = [
            'signatureId' => $message->signatureId,
            'signatureZoneIndex' => $message->signatureZoneIndex,
            'content' => base64_encode($message->content),
        ];

        return [
            'body' => json_encode($data, JSON_THROW_ON_ERROR),
            'headers' => [],
        ];
    }
}
