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

use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Repository\StoredObjectRepositoryInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
use Symfony\Component\Serializer\Exception\LogicException;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\ObjectToPopulateTrait;

/**
 * Implements the DenormalizerInterface and is responsible for denormalizing data into StoredObject objects.
 *
 * If a new StoredObjectVersion has been added to the StoredObject, the version is created here and registered
 * to the StoredObject.
 */
class StoredObjectDenormalizer implements DenormalizerInterface
{
    use ObjectToPopulateTrait;

    public function __construct(private readonly StoredObjectRepositoryInterface $storedObjectRepository) {}

    public function denormalize($data, $type, $format = null, array $context = []): ?StoredObject
    {
        $storedObject = $this->extractObjectToPopulate(StoredObject::class, $context);

        if (null === $storedObject) {
            if (array_key_exists('uuid', $data)) {
                $storedObject = $this->storedObjectRepository->findOneByUUID($data['uuid']);
            } else {
                $storedObject = $this->storedObjectRepository->find($data['id']);
            }

            if (null === $storedObject) {
                throw new LogicException('Object not found');
            }
        }

        $storedObject->setTitle($data['title'] ?? $storedObject->getTitle());

        if (true === ($data['currentVersion']['persisted'] ?? true)) {
            // nothing has change, stop here
            return $storedObject;
        }

        if ([] !== $diff = array_diff(['filename', 'iv', 'keyInfos', 'type'], array_keys($data['currentVersion']))) {
            throw new TransformationFailedException(sprintf('missing some keys in currentVersion: %s', implode(', ', $diff)));
        }

        $storedObject->registerVersion(
            $data['currentVersion']['iv'],
            $data['currentVersion']['keyInfos'],
            $data['currentVersion']['type'],
            $data['currentVersion']['filename']
        );

        return $storedObject;
    }

    public function supportsDenormalization($data, $type, $format = null): bool
    {
        if (StoredObject::class !== $type) {
            return false;
        }

        if (false === is_array($data)) {
            return false;
        }

        if (array_key_exists('id', $data) || array_key_exists('uuid', $data)) {
            return true;
        }

        return false;
    }
}
