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

use Chill\TicketBundle\Entity\Motive;
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;

/**
 * Normalizes a Motive object into an array format, supporting different serialization groups
 * to customize the output depending on the context.
 *
 * There are several serialization groups available:
 * - 'read': Basic information about the motive.
 * - 'read:extended': Includes additional details like stored objects and supplementary comments.
 * - 'read:parent-to-children': Normalizes children recursively without exposing parent to avoid cycles.
 * - 'read:children-to-parent': Normalizes parent recursively without exposing children to avoid cycles.
 */
final class MotiveNormalizer implements NormalizerInterface, NormalizerAwareInterface
{
    use NormalizerAwareTrait;

    public const GROUP_PARENT_TO_CHILDREN = 'read:parent-to-children';
    public const GROUP_CHILDREN_TO_PARENT = 'read:children-to-parent';

    public function normalize($object, ?string $format = null, array $context = []): array
    {
        if (!$object instanceof Motive) {
            throw new UnexpectedValueException('Expected instance of '.Motive::class);
        }

        $groups = $context[AbstractNormalizer::GROUPS] ?? [];
        if (is_string($groups)) {
            $groups = [$groups];
        }

        $data = [];

        if (in_array('read', $groups, true) || in_array('read:extended', $groups, true)) {
            // Build base representation
            $data = [
                'type' => 'ticket_motive',
                'id' => $object->getId(),
                'label' => $object->getLabel(),
                'active' => $object->isActive(),
            ];
        }

        if (in_array('read:extended', $groups, true)) {
            $data['makeTicketEmergency'] = $object->getMakeTicketEmergency();
            $data['supplementaryComments'] = $object->getSupplementaryComments();
            // Normalize stored objects (delegated to their own normalizer when present)
            $storedObjects = [];
            foreach ($object->getStoredObjects() as $storedObject) {
                $storedObjects[] = $this->normalizer->normalize($storedObject, $format, $context);
            }
            $data['storedObjects'] = $storedObjects;

        }

        if (in_array(self::GROUP_PARENT_TO_CHILDREN, $groups, true)) {
            // Normalize children recursively (but we do not expose parent to avoid cycles)
            $children = [];
            foreach ($object->getChildren() as $child) {
                $children[] = $this->normalizer->normalize($child, $format, $context);
            }
            $data['children'] = $children;
        } elseif (in_array(self::GROUP_CHILDREN_TO_PARENT, $groups, true)) {
            $data['parent'] = $this->normalizer->normalize($object->getParent(), $format, $context);
        }

        return $data;
    }

    public function supportsNormalization($data, ?string $format = null, array $context = []): bool
    {
        return $data instanceof Motive;
    }

    /**
     * Optimization hint for the Serializer (available since Symfony 5.3+).
     *
     * @return array<class-string, bool>
     */
    public function getSupportedTypes(?string $format): array
    {
        return [
            Motive::class => true,
        ];
    }
}
