<?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\ActivityBundle\Repository\ActivityRepository;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
use Chill\PersonBundle\Templating\Entity\SocialIssueRender;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;

class AccompanyingPeriodValidityValidator extends ConstraintValidator
{
    public function __construct(private readonly ActivityRepository $activityRepository, private readonly SocialIssueRender $socialIssueRender, private readonly TokenStorageInterface $token) {}

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

        if (!$period instanceof AccompanyingPeriod) {
            throw new UnexpectedValueException($period, AccompanyingPeriod::class);
        }

        /** Check if a social issue can be deleted (is not linked to an action or activity within the parcours) */
        $socialIssues = [];

        $activities = $this->activityRepository->findBy(['accompanyingPeriod' => $period]);

        foreach ($activities as $activity) {
            $socialIssues = array_merge($socialIssues, $activity->getSocialIssues()->toArray());
        }

        foreach ($period->getWorks() as $work) {
            $socialIssues[] = $work->getSocialAction()->getIssue();
        }

        $socialIssuesByKey = [];

        foreach ($socialIssues as $si) {
            $socialIssuesByKey[spl_object_hash($si)] = $si;
        }

        $periodIssuesWithAncestors = [];

        foreach ($period->getSocialIssues() as $si) {
            /** @var SocialIssue $si */
            $periodIssuesWithAncestors = array_merge(
                $periodIssuesWithAncestors,
                array_map(
                    static fn (SocialIssue $si) => spl_object_hash($si),
                    $si->getAncestors(true)
                )
            );
        }

        foreach ($socialIssuesByKey as $key => $si) {
            if (!\in_array($key, $periodIssuesWithAncestors, true)) {
                $this->context
                    ->buildViolation(
                        $constraint->messageSocialIssueCannotBeDeleted
                    )
                    ->setParameter('%name%', $this->socialIssueRender->renderString($si, []))
                    ->addViolation();
            }
        }
    }
}
