<?php
declare(strict_types=1);

namespace App\Serializer;

use App\Entity\Access\Access;
use App\Service\Utils\EntityUtils;
use ArrayObject;
use ReflectionException;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\Serializer\Exception\ExceptionInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\SerializerAwareInterface;
use Symfony\Component\Serializer\SerializerInterface;

/**
 * Serializer par défaut
 */
final class DefaultNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface
{
    public function __construct(
        private NormalizerInterface $decorated,
        private EntityUtils $entityUtils,
        private Security $security
    )
    {
        if (!$this->decorated instanceof DenormalizerInterface) {
            throw new \InvalidArgumentException(sprintf('The decorated normalizer must implement the %s.', DenormalizerInterface::class));
        }
    }

    /**
     * @param $data
     * @param $format
     * @param mixed[] $context
     * @return bool
     */
    public function supportsNormalization($data, $format = null, array $context = []): bool
    {
        return $this->decorated->supportsNormalization($data, $format);
    }

    /**
     * @param $object
     * @param $format
     * @param mixed[]  $context
     * @return mixed
     * @throws ExceptionInterface
     */
    public function normalize($object, $format = null, array $context = []): mixed
    {
        return $this->decorated->normalize($object, $format, $context);
    }

    /**
     * @param $data
     * @param $type
     * @param $format
     * @param mixed[] $context
     * @return bool
     */
    public function supportsDenormalization($data, $type, $format = null, array $context = []): bool
    {
        /** @phpstan-ignore-next-line */
        return $this->decorated->supportsDenormalization($data, $type, $format);
    }

    /**
     * @param $data
     * @param $class
     * @param $format
     * @param mixed[] $context
     * @return mixed
     * @throws ReflectionException
     */
    public function denormalize($data, $class, $format = null, array $context = []): mixed
    {
        /** @phpstan-ignore-next-line */
        $entity = $this->decorated->denormalize($data, $class, $format, $context);

        /** @var Access $access */
        $access = $this->security->getUser();
        $this->entityUtils->defaultValueSettersByAccess($entity, $access);

        return $entity;
    }

    public function setSerializer(SerializerInterface $serializer): void
    {
        if($this->decorated instanceof SerializerAwareInterface) {
            $this->decorated->setSerializer($serializer);
        }
    }
}
