<?php

namespace AutoAdmin\Bundle\Content\Validator;

use AutoAdmin\Bundle\Content\Hierarchy\Model\Interfaces\SelfHierarchyInterface;
use AutoAdmin\Bundle\Content\Model\TranslationInterface;
use AutoAdmin\Bundle\Content\Repository\AbstractContentRepository;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;
use function is_string;

class UniqueSlugValidator extends ConstraintValidator
{
    public function __construct(
        private readonly EntityManagerInterface $entityManager,
    )
    {
    }

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

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

        if (!is_string($value)) {
            throw new UnexpectedValueException($value, 'string');
        }

        $entity = $this->context->getObject();
        $propertyName = $this->context->getPropertyName();
        $repository = $this->getRepository($entity);

        if ($repository instanceof AbstractContentRepository) {
            if ($entity instanceof TranslationInterface) {
                $alias = '_tr';
                $mainEntity = $entity->getTranslatable();
            } else {
                $alias = '_';
                $mainEntity = $entity;
            }

            $mainEntityId = $mainEntity->getId();
            $site = $mainEntity->getSite();

            $criteria = [
                $alias . '.' . $propertyName => $value,
                '_.site' => $site
            ];

            if ($mainEntity instanceof SelfHierarchyInterface) {
                $criteria['_.parent'] = $mainEntity->getParent();
            }

            $slugs = $repository->contentFindBy($criteria);

            $slugs = array_filter($slugs, fn($e) => $e->getId() !== $mainEntityId);

            if (empty($slugs)) {
                return;
            }
        }

        $this->context->buildViolation($constraint->message)
            ->setParameter('{{ property }}', $propertyName)
            ->setParameter('{{ value }}', $value)
            ->addViolation();
    }

    private function getRepository($entity): EntityRepository
    {
        if ($entity instanceof TranslationInterface) {
            return $this->entityManager->getRepository($entity->getTranslatable()::class);
        }

        return $this->entityManager->getRepository($entity::class);
    }
}
