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

use Chill\MainBundle\Export\ExportGenerationContext;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Form\Type\PickRollingDateType;
use Chill\MainBundle\Service\RollingDate\RollingDate;
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
use Chill\PersonBundle\Export\Declarations;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;

class HasTemporaryLocationFilter implements FilterInterface
{
    public function __construct(private readonly RollingDateConverterInterface $rollingDateConverter) {}

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

    public function alterQuery(QueryBuilder $qb, $data, ExportGenerationContext $exportGenerationContext): void
    {
        $qb
            ->join('acp.locationHistories', 'acp_having_temporarily_location')
            ->andWhere('acp_having_temporarily_location.startDate <= :acp_having_temporarily_location_date
                 AND (acp_having_temporarily_location.endDate IS NULL OR acp_having_temporarily_location.endDate > :acp_having_temporarily_location_date)')
            ->setParameter(
                'acp_having_temporarily_location_date',
                $this->rollingDateConverter->convert($data['calc_date'])
            );

        match ($data['having_temporarily']) {
            true => $qb->andWhere('acp_having_temporarily_location.addressLocation IS NOT NULL'),
            false => $qb->andWhere('acp_having_temporarily_location.personLocation IS NOT NULL'),
            default => throw new \LogicException('value not supported'),
        };
    }

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

    public function buildForm(FormBuilderInterface $builder): void
    {
        $builder
            ->add('having_temporarily', ChoiceType::class, [
                'label' => 'export.filter.course.having_temporarily.label',
                'choices' => [
                    'export.filter.course.having_temporarily.Having a temporarily location' => true,
                    'export.filter.course.having_temporarily.Having a person\'s location' => false,
                ],
                'choice_label' => static fn ($choice) => match ($choice) {
                    true => 'export.filter.course.having_temporarily.Having a temporarily location',
                    false => 'export.filter.course.having_temporarily.Having a person\'s location',
                    default => throw new \LogicException('this choice is not supported'),
                },
            ])
            ->add('calc_date', PickRollingDateType::class, [
                'label' => 'export.filter.course.having_temporarily.Calculation date',
                'required' => true,
            ]);
    }

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

    public function normalizeFormData(array $formData): array
    {
        return ['having_temporarily' => $formData['having_temporarily'], 'calc_date' => $formData['calc_date']->normalize()];
    }

    public function denormalizeFormData(array $formData, int $fromVersion): array
    {
        return ['having_temporarily' => $formData['having_temporarily'], 'calc_date' => RollingDate::fromNormalized($formData['calc_date'])];
    }

    public function getFormDefaultData(): array
    {
        return ['calc_date' => new RollingDate(RollingDate::T_TODAY)];
    }

    public function describeAction($data, ExportGenerationContext $context): array
    {
        return match ($data['having_temporarily']) {
            true => ['export.filter.course.having_temporarily.Having a temporarily location', []],
            false => ['export.filter.course.having_temporarily.Having a person\'s location', []],
            default => throw new \LogicException('value not supported'),
        };
    }

    public function getTitle(): string
    {
        return 'Filter by temporary location';
    }
}
