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

use Chill\MainBundle\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

class UserUniqueEmailAndUsername extends ConstraintValidator
{
    /**
     * @var EntityManagerInterface
     */
    protected $em;

    public function __construct(EntityManagerInterface $em)
    {
        $this->em = $em;
    }

    public function validate($value, Constraint $constraint)
    {
        if (!$value instanceof User) {
            throw new \UnexpectedValueException('This validation should happens only on class '.User::class);
        }

        if (null !== $value->getId()) {
            $countUsersByUsername = $this->em->createQuery(
                sprintf(
                    'SELECT COUNT(u) FROM %s u '
                    .'WHERE u.usernameCanonical = LOWER(UNACCENT(:username)) '
                    .'AND u != :user',
                    User::class
                )
            )
                ->setParameter('username', $value->getUsername())
                ->setParameter('user', $value)
                ->getSingleScalarResult();
        } else {
            $countUsersByUsername = $this->em->createQuery(
                sprintf(
                    'SELECT COUNT(u) FROM %s u '
                    .'WHERE u.usernameCanonical = LOWER(UNACCENT(:username)) ',
                    User::class
                )
            )
                ->setParameter('username', $value->getUsername())
                ->getSingleScalarResult();
        }

        if (0 < $countUsersByUsername) {
            $this->context
                ->buildViolation($constraint->messageDuplicateUsername)
                ->setParameters([
                    '%username%' => $value->getUsername(),
                ])
                ->atPath('username')
                ->addViolation();
        }

        if (null !== $value->getId()) {
            $countUsersByEmail = $this->em->createQuery(
                sprintf(
                    'SELECT COUNT(u) FROM %s u '
                    .'WHERE u.emailCanonical = LOWER(UNACCENT(:email)) '
                    .'AND u != :user',
                    User::class
                )
            )
                ->setParameter('email', $value->getEmail())
                ->setParameter('user', $value)
                ->getSingleScalarResult();
        } else {
            $countUsersByEmail = $this->em->createQuery(
                sprintf(
                    'SELECT COUNT(u) FROM %s u '
                    .'WHERE u.emailCanonical = LOWER(UNACCENT(:email))',
                    User::class
                )
            )
                ->setParameter('email', $value->getEmail())
                ->getSingleScalarResult();
        }

        if (0 < $countUsersByEmail) {
            $this->context
                ->buildViolation($constraint->messageDuplicateEmail)
                ->setParameters([
                    '%email%' => $value->getEmail(),
                ])
                ->atPath('email')
                ->addViolation();
        }
    }
}
