<?php

declare(strict_types=1);

/*
 * This file is part of the Ferienpass package.
 *
 * (c) Richard Henkenjohann <richard@ferienpass.online>
 *
 * For more information visit the project website <https://ferienpass.online>
 * or the documentation under <https://docs.ferienpass.online>.
 */

namespace Ferienpass\CoreBundle\Validator;

use Ferienpass\CmsBundle\Dto\AccessCodeDto;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;

class AccessCodeValidator extends ConstraintValidator
{
    public function validate(mixed $value, Constraint $constraint): void
    {
        if (!$constraint instanceof ValidAccessCode) {
            throw new UnexpectedTypeException($constraint, ValidAccessCode::class);
        }

        if (null === $value) {
            return;
        }

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

        $code = trim($value->getCode() ?? '');
        if ('' === $code) {
            return;
        }

        $accessCode = $value->getAccessCodeStrategy()->findCode($code);
        if ($accessCode instanceof \Ferienpass\CoreBundle\Entity\AccessCode && (false === $constraint->checkUsage || !$value->getAccessCodeStrategy()->getMax() || $accessCode->getParticipants()->count() < $value->getAccessCodeStrategy()->getMax())) {
            return;
        }

        $this->context->buildViolation($constraint->message)
            ->setParameter('{{ string }}', $code)
            ->atPath('code')
            ->addViolation()
        ;
    }
}
