<?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\GenericDoc\Exception\AssociatedStoredObjectNotFound;
use Chill\DocStoreBundle\GenericDoc\GenericDocDTO;
use Chill\DocStoreBundle\GenericDoc\ManagerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;

class GenericDocNormalizer implements NormalizerInterface, NormalizerAwareInterface
{
    use NormalizerAwareTrait;

    /**
     * Special key to attach a stored object to the generic doc.
     *
     * This is present for performance reason: if any other part of the application "knows" about the stored object
     * related to the GenericDoc, this stored object is use instead of adding costly sql queries.
     */
    public const ATTACHED_STORED_OBJECT_PROXY = 'attached-stored-object-proxy';

    public function __construct(private readonly ManagerInterface $manager) {}

    public function normalize($object, ?string $format = null, array $context = []): array
    {
        /* @var GenericDocDTO $object */

        try {
            $storedObject = $context[self::ATTACHED_STORED_OBJECT_PROXY] ?? $this->manager->fetchStoredObject($object);
        } catch (AssociatedStoredObjectNotFound) {
            $storedObject = null;
        }

        $data = [
            'type' => 'doc_store_generic_doc',
            'key' => $object->key,
            'uniqueKey' => $object->key.implode('', array_keys($object->identifiers)).implode('', array_values($object->identifiers)),
            'identifiers' => $object->identifiers,
            'context' => $object->getContext(),
            'doc_date' => $this->normalizer->normalize($object->docDate, $format, $context),
            'metadata' => [],
            'storedObject' => $this->normalizer->normalize($storedObject, $format, $context),
        ];

        if ($this->manager->isGenericDocNormalizable($object, $format, $context)) {
            $data['metadata'] = $this->manager->normalizeGenericDoc($object, $format, $context);
        }

        return $data;
    }

    public function supportsNormalization($data, ?string $format = null): bool
    {
        return 'json' === $format && $data instanceof GenericDocDTO;
    }
}
