<?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\Export\Filter\PersonFilters;

use Chill\MainBundle\Entity\Country;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Export\ExportGenerationContext;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Form\Type\Select2CountryType;
use Chill\MainBundle\Repository\CountryRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\PersonBundle\Export\Declarations;
use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface;

final readonly class NationalityFilter implements
    ExportElementValidatedInterface,
    FilterInterface
{
    use \Chill\MainBundle\Export\ExportDataNormalizerTrait;

    public function __construct(private TranslatableStringHelper $translatableStringHelper, private CountryRepository $countryRepository) {}

    public function addRole(): ?string
    {
        return null;
    }

    public function alterQuery(QueryBuilder $qb, $data, ExportGenerationContext $exportGenerationContext): void
    {
        $where = $qb->getDQLPart('where');
        $clause = $qb->expr()->in('person.nationality', ':person_nationality');

        if ($where instanceof Expr\Andx) {
            $where->add($clause);
        } else {
            $where = $qb->expr()->andX($clause);
        }

        $qb->add('where', $where);
        $qb->setParameter('person_nationality', [$data['nationalities']]);
    }

    public function applyOn(): string
    {
        return Declarations::PERSON_TYPE;
    }

    public function buildForm(FormBuilderInterface $builder): void
    {
        $builder->add('nationalities', Select2CountryType::class, [
            'placeholder' => 'Choose countries',
        ]);
    }

    public function getNormalizationVersion(): int
    {
        return 1;
    }

    public function normalizeFormData(array $formData): array
    {
        return ['nationalities' => $this->normalizeDoctrineEntity($formData['nationalities'])];
    }

    public function denormalizeFormData(array $formData, int $fromVersion): array
    {
        return ['nationalities' => $this->denormalizeDoctrineEntity($formData['nationalities'], $this->countryRepository)];
    }

    public function getFormDefaultData(): array
    {
        return [];
    }

    public function describeAction($data, ExportGenerationContext $context): string|\Symfony\Contracts\Translation\TranslatableInterface|array
    {
        $countries = $data['nationalities'];

        $names = array_map(fn (Country $c) => $this->translatableStringHelper->localize($c->getName()), [$countries]);

        return [
            'Filtered by nationality : %nationalities%',
            ['%nationalities%' => implode(', ', $names)],
        ];
    }

    public function getTitle(): string|\Symfony\Contracts\Translation\TranslatableInterface
    {
        return "Filter by person's nationality";
    }

    public function validateForm($data, ExecutionContextInterface $context): void
    {
        if (null === $data['nationalities']) {
            $context->buildViolation('A nationality must be selected')
                ->addViolation();
        }
    }
}
