<?php

declare(strict_types=1);

namespace CpCreation\VitiCore\Bridge\Symfony\Bundle\Validator\Constraints;

use CpCreation\VitiCore\Cart\Model\Promo;
use CpCreation\VitiCore\Cart\Repository\PromoRepository;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;

final class PromoTitleAvailabilityValidator extends ConstraintValidator
{
    public function __construct(
        private readonly PromoRepository $promoRepository,
    ) {
    }

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

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

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

        if (null === $value->getTitle() || '' === $value->getTitle()) {
            return;
        }

        $duplicates = $this->promoRepository->findOtherPromosWithSameTitle($value);

        if ([] === $duplicates) {
            return;
        }

        if ($value->isAuto()) {
            foreach ($duplicates as $duplicate) {
                if (!$duplicate->isAuto()) {
                    $this->addViolation($constraint);

                    return;
                }
            }

            return;
        }

        $this->addViolation($constraint);
    }

    private function addViolation(PromoTitleAvailability $constraint): void
    {
        $this->context
            ->buildViolation($constraint->message)
            ->atPath('title')
            ->addViolation();
    }
}
