<?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\Phonenumber\PhoneNumberHelperInterface;
use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface;
use Chill\MainBundle\Templating\Entity\ChillEntityRenderExtension;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\PersonAltName;
use Chill\PersonBundle\Repository\ResidentialAddressRepository;
use Doctrine\Common\Collections\Collection;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;

/**
 * Serialize a Person entity.
 */
class PersonJsonNormalizer implements NormalizerAwareInterface, NormalizerInterface
{
    use NormalizerAwareTrait;

    public function __construct(
        private readonly ChillEntityRenderExtension $render,
        private readonly CenterResolverManagerInterface $centerResolverManager,
        private readonly ResidentialAddressRepository $residentialAddressRepository,
        private readonly PhoneNumberHelperInterface $phoneNumberHelper,
        private readonly \Chill\PersonBundle\PersonIdentifier\Rendering\PersonIdRenderingInterface $personIdRendering,
    ) {}

    /**
     * @param Person      $person
     * @param string|null $format
     */
    public function normalize($person, $format = null, array $context = [])
    {
        $groups = $context[AbstractNormalizer::GROUPS] ?? [];

        if (\is_string($groups)) {
            $groups = [$groups];
        }
        $household = $person->getCurrentHousehold();
        $currentResidentialAddresses = $this->residentialAddressRepository->findCurrentResidentialAddressByPerson($person);

        $data = [
            'type' => 'person',
            'id' => $person->getId(),
            'text' => $this->render->renderString($person, ['addAge' => false]),
            'textAge' => $this->render->renderString($person, ['addAge' => true]),
            'firstName' => $person->getFirstName(),
            'lastName' => $person->getLastName(),
            'current_household_address' => $this->normalizer->normalize($person->getCurrentHouseholdAddress(), $format, $context),
            'birthdate' => $this->normalizer->normalize($person->getBirthdate(), $format, $context),
            'deathdate' => $this->normalizer->normalize($person->getDeathdate(), $format, $context),
            'age' => $this->normalizer->normalize($person->getAge(), $format, $context),
            'phonenumber' => $this->normalizer->normalize($person->getPhonenumber(), $format, $context),
            'mobilenumber' => $this->normalizer->normalize($person->getMobilenumber(), $format, $context),
            'email' => $person->getEmail(),
            'gender' => $this->normalizer->normalize($person->getGender(), $format, $context),
            'civility' => $this->normalizer->normalize($person->getCivility(), $format, $context),
            'personId' => $this->personIdRendering->renderPersonId($person),
            'identifiers' => $this->normalizer->normalize($person->getIdentifiers(), $format, $context),
        ];

        if (\in_array('minimal', $groups, true) && 1 === \count($groups)) {
            return $data;
        }

        return [...$data, 'centers' => $this->normalizer->normalize($this->centerResolverManager->resolveCenters($person), $format, $context), 'altNames' => $this->normalizeAltNames($person->getAltNames()), 'current_household_id' => $household ? $this->normalizer->normalize($household->getId(), $format, $context) : null, 'current_residential_addresses' => $currentResidentialAddresses ?
            $this->normalizer->normalize($currentResidentialAddresses, $format, $context) :
            null];
    }

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

    /**
     * @param Collection<array-key, PersonAltName> $altNames
     *
     * @return array<array-key, array<string, string>>
     */
    protected function normalizeAltNames(Collection $altNames): array
    {
        return $altNames
            ->map(
                static fn (PersonAltName $personAltName): array => [
                    'key' => $personAltName->getKey(),
                    'label' => $personAltName->getLabel(),
                ]
            )
            ->toArray();
    }
}
