<?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\Validator\Exception\UnexpectedValueException;
use Symfony\Component\Workflow\Registry;

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

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

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

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

        $workflow = $this->registry->get($value->entityWorkflow, $value->entityWorkflow->getWorkflowName());
        $metadataStore = $workflow->getMetadataStore();

        $destUsersRequired = false;

        foreach ($value->transition->getTos() as $to) {
            $metadata = $metadataStore->getPlaceMetadata($to);

            // if the place are only 'isSentExternal' or 'isSignature' or 'final', then, we skip - a destUser is not required
            if ($metadata['isSentExternal'] ?? false) {
                continue;
            }
            if ($metadata['isSignature'] ?? false) {
                continue;
            }
            if ($metadata['isFinal'] ?? false) {
                continue;
            }
            // if there isn't any 'isSentExternal' or 'isSignature' or final, then we must have a destUser
            $destUsersRequired = true;
        }

        if (!$destUsersRequired) {
            if (0 < count($value->futureDestUsers)) {
                $this->context->buildViolation($constraint->messageDestUserNotAuthorized)
                    ->setCode($constraint->codeDestUserNotAuthorized)
                    ->atPath('futureDestUsers')
                    ->addViolation();
            }

            return;
        }

        if (0 === count($value->futureDestUsers)) {
            $this->context->buildViolation($constraint->messageDestUserRequired)
                ->setCode($constraint->codeDestUserRequired)
                ->atPath('futureDestUsers')
                ->addViolation();
        }
    }
}
