<?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\MainBundle\Workflow\Validator;

use Chill\MainBundle\Workflow\WorkflowTransitionContextDTO;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Workflow\Registry;

final class TransitionHasDestineeIfIsSentExternalValidator extends ConstraintValidator
{
    public function __construct(private readonly Registry $registry) {}

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

        if (!$value instanceof WorkflowTransitionContextDTO) {
            throw new UnexpectedTypeException($value, WorkflowTransitionContextDTO::class);
        }

        if (null == $value->transition) {
            return;
        }

        $workflow = $this->registry->get($value->entityWorkflow, $value->entityWorkflow->getWorkflowName());
        $isSentExternal = false;
        foreach ($value->transition->getTos() as $to) {
            $metadata = $workflow->getMetadataStore()->getPlaceMetadata($to);

            $isSentExternal = $isSentExternal ? true : $metadata['isSentExternal'] ?? false;
        }

        if (!$isSentExternal) {
            if (0 !== count($value->futureDestineeThirdParties)) {
                $this->context->buildViolation($constraint->messageDestineeRequired)
                    ->atPath('futureDestineeThirdParties')
                    ->setCode($constraint->codeDestineeUnauthorized)
                    ->addViolation();
            }
            if (0 !== count($value->futureDestineeEmails)) {
                $this->context->buildViolation($constraint->messageDestineeRequired)
                    ->atPath('futureDestineeEmails')
                    ->setCode($constraint->codeDestineeUnauthorized)
                    ->addViolation();
            }

            return;
        }

        if (0 === count($value->futureDestineeEmails) && 0 === count($value->futureDestineeThirdParties)) {
            $this->context->buildViolation($constraint->messageDestineeRequired)
                ->atPath('futureDestineeThirdParties')
                ->setCode($constraint->codeNoNecessaryDestinee)
                ->addViolation();
        }
    }
}
