<?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\Validator\Constraints\AccompanyingPeriod;

use Chill\MainBundle\Util\DateRangeCovering;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Templating\Entity\PersonRenderInterface;
use Chill\ThirdPartyBundle\Templating\Entity\ThirdPartyRender;
use Doctrine\Common\Collections\Collection;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;

class ParticipationOverlapValidator extends ConstraintValidator
{
    private const MAX_PARTICIPATION = 1;

    public function __construct(private readonly PersonRenderInterface $personRender, private readonly ThirdPartyRender $thirdpartyRender) {}

    public function validate($participations, Constraint $constraint)
    {
        if (!$constraint instanceof ParticipationOverlap) {
            throw new UnexpectedTypeException($constraint, ParticipationOverlap::class);
        }

        if (!$participations instanceof Collection) {
            throw new UnexpectedTypeException($participations, 'This should be a collection');
        }

        if (\count($participations) <= self::MAX_PARTICIPATION) {
            return;
        }

        if (0 === \count($participations)) {
            return;
        }

        $participationList = [];

        foreach ($participations as $participation) {
            if (!$participation instanceof AccompanyingPeriodParticipation) {
                throw new UnexpectedTypeException($participation, AccompanyingPeriodParticipation::class);
            }

            $hashPerson = spl_object_hash($participation->getPerson());

            $participationList[$hashPerson][] = $participation;
        }

        foreach ($participationList as $group) {
            if (\count($group) > 1) {
                $overlaps = new DateRangeCovering(self::MAX_PARTICIPATION, $participations[0]->getStartDate()->getTimezone());

                foreach ($group as $p) {
                    $overlaps->add($p->getStartDate(), $p->getEndDate(), $p->getId());
                }

                $overlaps->compute();

                if ($overlaps->hasIntersections()) {
                    foreach ($overlaps->getIntersections() as [$start, $end, $ids]) {
                        $msg = $constraint->message;

                        $this->context->buildViolation($msg)
                            ->setParameters([
                                '{{ start }}' => $start->format('d-m-Y'),
                                '{{ end }}' => null === $end ? null : $end->format('d-m-Y'),
                                '{{ ids }}' => $ids,
                                '{{ name }}' => $this->personRender->renderString($participations[0]->getPerson(), []),
                            ])
                            ->addViolation();
                    }
                }
            }
        }
    }
}
