<?php

declare(strict_types=1);

namespace NoahVet\Reef\RabbitMQ\Serializer\Normalizer;

use NoahVet\Reef\RabbitMQ\Notification\ReefNotification;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;

class ReefNotificationNormalizer implements DenormalizerInterface, NormalizerInterface
{
    /**
     * @param array{
     *      type: string,
     *      client_id: string,
     *      resource_type: string,
     *      resource_id: string,
     *      action: string,
     *      raw_data?: array<mixed>,
     *  } $data
     */
    public function denormalize($data, string $type, ?string $format = null, array $context = []): ReefNotification
    {
        return new ReefNotification(
            $data['client_id'],
            $data['resource_type'],
            $data['resource_id'],
            $data['action'],
            $data['raw_data'] ?? [],
        );
    }

    /**
     * @return array<class-string|'*'|'object'|string, bool|null>
     */
    public function getSupportedTypes(?string $format): array
    {
        return [
            ReefNotification::class => true,
        ];
    }

    /**
     * @param array<mixed> $context
     */
    public function supportsDenormalization($data, string $type, ?string $format = null, array $context = []): bool
    {
        return \is_array($data)
            && ($data['type'] ?? '') === ReefNotification::class
            && \is_string($data['client_id'] ?? null)
            && \is_string($data['resource_type'] ?? null)
            && \is_string($data['resource_id'] ?? null)
            && \is_string($data['action'] ?? null)
            && \is_array($data['raw_data'] ?? []);
    }

    /**
     * @return array{
     *     type: string,
     *     client_id: string,
     *     resource_type: string,
     *     resource_id: string,
     *     action: string,
     *     raw_data: array<mixed>,
     * }
     */
    public function normalize($object, ?string $format = null, array $context = []): array
    {
        \assert($object instanceof ReefNotification);

        return [
            'type' => ReefNotification::class,
            'client_id' => $object->clientId,
            'resource_type' => $object->resourceType,
            'resource_id' => $object->resourceId,
            'action' => $object->action,
            'raw_data' => $object->rawData,
        ];
    }

    /**
     * @param array<mixed> $context
     */
    public function supportsNormalization($data, ?string $format = null, array $context = []): bool
    {
        return $data instanceof ReefNotification;
    }
}
