<?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\Aggregator\PersonAggregators;

use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Form\Type\PickRollingDateType;
use Chill\MainBundle\Service\RollingDate\RollingDate;
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\PersonBundle\Entity\Household\HouseholdMember;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Repository\Household\PositionRepository;
use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Contracts\Translation\TranslatorInterface;

final readonly class HouseholdPositionAggregator implements AggregatorInterface, ExportElementValidatedInterface
{
    public function __construct(private TranslatorInterface $translator, private TranslatableStringHelper $translatableStringHelper, private PositionRepository $positionRepository, private RollingDateConverterInterface $rollingDateConverter) {}

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

    public function alterQuery(QueryBuilder $qb, $data, \Chill\MainBundle\Export\ExportGenerationContext $exportGenerationContext): void
    {
        if (!\in_array('householdmember', $qb->getAllAliases(), true)) {
            $qb->join(HouseholdMember::class, 'householdmember', Expr\Join::WITH, 'householdmember.person = person');
        }

        if (!\in_array('center', $qb->getAllAliases(), true)) {
            $qb->join('person.center', 'center');
        }

        $qb->andWhere($qb->expr()->andX(
            $qb->expr()->lte('householdmember.startDate', ':date'),
            $qb->expr()->orX(
                $qb->expr()->isNull('householdmember.endDate'),
                $qb->expr()->gte('householdmember.endDate', ':date')
            )
        ));

        $qb->setParameter(
            'date',
            $this->rollingDateConverter->convert($data['date_position'])
        );

        $qb->addSelect('IDENTITY(householdmember.position) AS household_position_aggregator');
        $qb->addGroupBy('household_position_aggregator');
    }

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

    public function buildForm(FormBuilderInterface $builder): void
    {
        $builder->add('date_position', PickRollingDateType::class, [
            'label' => 'Household position in relation to this date',
        ]);
    }

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

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

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

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

    public function getLabels($key, array $values, $data): callable
    {
        return function ($value) {
            if ('_header' === $value) {
                return 'Household position';
            }

            if (null === $value || '' === $value) {
                return $this->translator->trans('without data');
            }

            $p = $this->positionRepository->find($value);

            return $this->translatableStringHelper->localize($p->getLabel());
        };
    }

    public function getQueryKeys($data): array
    {
        return [
            'household_position_aggregator',
        ];
    }

    public function getTitle(): string|\Symfony\Contracts\Translation\TranslatableInterface
    {
        return 'Aggregate by household position';
    }

    public function validateForm($data, ExecutionContextInterface $context): void
    {
        if (null === $data['date_position']) {
            $context->buildViolation('The date should not be empty')
                ->addViolation();
        }
    }
}
