<?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;

use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Export\ExportGenerationContext;
use Chill\MainBundle\Export\FilterInterface;
use DateTime;
use Doctrine\ORM\Query\Expr;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Validator\Context\ExecutionContextInterface;

class BirthdateFilter implements ExportElementValidatedInterface, FilterInterface
{
    use \Chill\MainBundle\Export\ExportDataNormalizerTrait;
    // add specific role for this filter
    public function addRole(): ?string
    {
        // we do not need any new role for this filter, so we return null
        return null;
    }

    // here, we alter the query created by Export
    public function alterQuery(\Doctrine\ORM\QueryBuilder $qb, $data, \Chill\MainBundle\Export\ExportGenerationContext $exportGenerationContext): void
    {
        $where = $qb->getDQLPart('where');
        // we create the clause here
        $clause = $qb->expr()->between(
            'person.birthdate',
            ':date_from',
            ':date_to'
        );

        // we have to take care **not to** remove previous clauses...
        if ($where instanceof Expr\Andx) {
            $where->add($clause);
        } else {
            $where = $qb->expr()->andX($clause);
        }

        $qb->add('where', $where);
        // we add parameters from $data. $data contains the parameters from the form
        $qb->setParameter('date_from', $data['date_from']);
        $qb->setParameter('date_to', $data['date_to']);
    }

    // we give information on which type of export this filter applies
    public function applyOn(): string
    {
        return 'person';
    }

    // we build a form to collect some parameters from the users
    public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder): void
    {
        $builder->add('date_from', DateType::class, [
            'label' => 'Born after this date',
            'attr' => ['class' => 'datepicker'],
            'widget' => 'single_text',
            'format' => 'dd-MM-yyyy',
        ]);

        $builder->add('date_to', DateType::class, [
            'label' => 'Born before this date',
            'attr' => ['class' => 'datepicker'],
            'widget' => 'single_text',
            'format' => 'dd-MM-yyyy',
        ]);
    }
    public function getNormalizationVersion(): int
    {
        return 1;
    }
    public function normalizeFormData(array $formData): array
    {
        return ['date_from' => $this->normalizeDate($formData['date_from']), 'date_to' => $this->normalizeDate($formData['date_to'])];
    }
    public function denormalizeFormData(array $formData, int $fromVersion): array
    {
        return ['date_from' => $this->denormalizeDate($formData['date_from']), 'date_to' => $this->denormalizeDate($formData['date_to'])];
    }
    public function getFormDefaultData(): array
    {
        return ['date_from' => new DateTime(), 'date_to' => new DateTime()];
    }

    // here, we create a simple string which will describe the action of
    // the filter in the Response
    public function describeAction($data, ExportGenerationContext $context): string|\Symfony\Contracts\Translation\TranslatableInterface|array
    {
        return ['Filtered by person\'s birtdate: '
            . 'between %date_from% and %date_to%', [
                '%date_from%' => $data['date_from']->format('d-m-Y'),
                '%date_to%' => $data['date_to']->format('d-m-Y'),
            ], ];
    }

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

    // the form created above must be validated. The process of validation
    // is executed here. This function is added by the interface
    // `ExportElementValidatedInterface`, and can be ignore if there is
    // no need for a validation
    public function validateForm($data, ExecutionContextInterface $context): void
    {
        $date_from = $data['date_from'];
        $date_to = $data['date_to'];

        if (null === $date_from) {
            $context->buildViolation('The "date from" should not be empty')
                //->atPath('date_from')
                ->addViolation();
        }

        if (null === $date_to) {
            $context->buildViolation('The "date to" should not be empty')
                //->atPath('date_to')
                ->addViolation();
        }

        if (
            (null !== $date_from && null !== $date_to)
            && $date_from >= $date_to
        ) {
            $context->buildViolation('The date "date to" should be after the '
                . 'date given in "date from" field')
                ->addViolation();
        }
    }
}
