<?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\PersonBundle\Serializer\Normalizer;

use Chill\MainBundle\Serializer\Normalizer\DiscriminatedObjectDenormalizer;
use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Repository\AccompanyingPeriod\ResourceRepository;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Symfony\Component\Serializer\Exception;
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\ObjectToPopulateTrait;

class AccompanyingPeriodResourceNormalizer implements DenormalizerAwareInterface, DenormalizerInterface
{
    use DenormalizerAwareTrait;

    use ObjectToPopulateTrait;

    public function __construct(private readonly ResourceRepository $repository) {}

    public function denormalize($data, $type, $format = null, array $context = [])
    {
        $resource = $this->extractObjectToPopulate($type, $context);

        if ('accompanying_period_resource' !== ($data['type'] ?? null)) {
            throw new Exception\InvalidArgumentException("the key type must be present in data and set to 'accompanying_period_resource'");
        }

        if (null === $resource && \array_key_exists('id', $data)) {
            $resource = $this->repository->find($data['id']);

            if (null === $resource) {
                throw new Exception\UnexpectedValueException(sprintf('the resource withid %d is not found', $data['id']));
            }

            // if resource found, available only for read-only
            if (\count($data) > 2) {
                unset($data['id'], $data['type']);

                throw new Exception\ExtraAttributesException($data);
            }
        }

        if (null === $resource) {
            $resource = new Resource();
        }

        if (\array_key_exists('resource', $data)) {
            $res = $this->denormalizer->denormalize(
                $data['resource'],
                DiscriminatedObjectDenormalizer::TYPE,
                $format,
                \array_merge(
                    $context,
                    [
                        DiscriminatedObjectDenormalizer::ALLOWED_TYPES => [
                            Person::class, ThirdParty::class,
                        ],
                    ]
                )
            );

            $resource->setResource($res);
        }

        if (\array_key_exists('comment', $data)) {
            $resource->setComment($data['comment']);
        }

        return $resource;
    }

    public function normalize($resource, $format = null, array $context = [])
    {
        return [
            'type' => 'accompanying_period_resource',
            'id' => $resource->getId(),
            'comment' => $resource->getComment(),
        ];
    }

    public function supportsDenormalization($data, $type, $format = null)
    {
        return Resource::class === $type;
    }
}
