<?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\Repository;

use Doctrine\ORM\QueryBuilder;
use Ferienpass\CoreBundle\Dto\ParticipantDuplicateDto;
use Ferienpass\CoreBundle\Entity\Participant\ParticipantInterface;
use Ferienpass\CoreBundle\Entity\ParticipantDuplicate;
use Ferienpass\CoreBundle\Entity\User;
use Symfony\Component\Uid\Uuid;

class ParticipantRepository extends EntityRepository implements ParticipantRepositoryInterface
{
    public function createNew(?User $user = null): ParticipantInterface
    {
        $className = $this->getClassName();

        return new $className($user);
    }

    public function findByUuid(string|Uuid $uuid): ?ParticipantInterface
    {
        return $this->findOneBy(['uuid' => $uuid]);
    }

    public function queryAllDuplicates(): QueryBuilder
    {
        $qb = $this->createQueryBuilder('p1');
        $qb
            ->select(\sprintf('p1, NEW %s(p1.id, p2.id, (CASE WHEN d.type IS NULL THEN \'unconfirmed\' ELSE d.type END), p1.firstname, p1.lastname, p1.email, p1.uuid, p1.dateOfBirth, p2.firstname, p2.lastname, p2.email, p2.uuid, p2.dateOfBirth, u1.firstname, u1.lastname, u1.id, (SELECT COUNT(a1.id) FROM Ferienpass\CoreBundle\Entity\Attendance a1 WHERE a1.participant = p1), (SELECT COUNT(au1.id) FROM Ferienpass\CoreBundle\Entity\Attendance au1 JOIN au1.participant pu1 WHERE pu1.user = u1), u2.firstname, u2.lastname, u2.id, (SELECT COUNT(a2.id) FROM Ferienpass\CoreBundle\Entity\Attendance a2 WHERE a2.participant = p2), (SELECT COUNT(au2.id) FROM Ferienpass\CoreBundle\Entity\Attendance au2 JOIN au2.participant pu2 WHERE pu2.user = u2))', ParticipantDuplicateDto::class))
            ->innerJoin($this->getClassName(), 'p2', 'WITH', 'p1.firstname = p2.firstname AND p1.lastname = p2.lastname AND p1.id < p2.id')
            ->leftJoin('p1.user', 'u1')
            ->leftJoin('p2.user', 'u2')
            ->leftJoin(ParticipantDuplicate::class, 'd', 'WITH', 'd.participant = p1 AND d.duplicate = p2')
            ->where('d.type IS NULL OR d.type IN (:types)')
            ->setParameter('types', [ParticipantDuplicate::TYPE_TOLERATED])
            ->orderBy("CASE WHEN d.type IS NULL THEN 'unconfirmed' ELSE d.type END", 'DESC')
        ;

        return $qb;
    }
}
