<?php

declare(strict_types=1);

namespace App\Repository;

use App\Entity\Event;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use DateTimeImmutable;

/**
 * @extends ServiceEntityRepository<Event>
 *
 * @method Event|null find($id, $lockMode = null, $lockVersion = null)
 * @method Event|null findOneBy(array $criteria, array $orderBy = null)
 * @method Event[]    findAll()
 * @method Event[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
 */
class EventRepository extends ServiceEntityRepository
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, Event::class);
    }

    public function save(Event $event, bool $flush = false): void
    {
        $this->getEntityManager()->persist($event);

        if ($flush) {
            $this->getEntityManager()->flush();
        }
    }

    public function remove(Event $event, bool $flush = false): void
    {
        $this->getEntityManager()->remove($event);

        if ($flush) {
            $this->getEntityManager()->flush();
        }
    }

    /**
     * @return Event[] Returns an array of Event objects
     */
    public function findByName(string $name): array
    {
        return $this->createQueryBuilder('e')
            ->andWhere('e.name LIKE :name')
            ->setParameter('name', '%' . $name . '%')
            ->orderBy('e.createdAt', 'DESC')
            ->getQuery()
            ->getResult();
    }

    public function findOneByEventIdentifier(string $eventIdentifier): ?Event
    {
        return $this->createQueryBuilder('e')
            ->andWhere('e.eventIdentifier = :eventIdentifier')
            ->setParameter('eventIdentifier', $eventIdentifier)
            ->getQuery()
            ->getOneOrNullResult();
    }

    /**
     * @return Event[] Returns an array of Event objects that need pre or follow events
     */
    public function findAllNeedingPreOrFollowEvent(): array
    {
        return $this->createQueryBuilder('e')
            ->andWhere('e.needsPreOrFollowEvent = :needsPreOrFollowEvent')
            ->setParameter('needsPreOrFollowEvent', true)
            ->orderBy('e.createdAt', 'DESC')
            ->getQuery()
            ->getResult();
    }

    /**
     * @return Event[] Returns an array of Event objects with direct pre-follow relationship
     */
    public function findAllWithDirectPreFollow(): array
    {
        return $this->createQueryBuilder('e')
            ->andWhere('e.directPreFollow = :directPreFollow')
            ->setParameter('directPreFollow', true)
            ->orderBy('e.createdAt', 'DESC')
            ->getQuery()
            ->getResult();
    }

    /**
     * Find events created after a specific date
     *
     * @return Event[] Returns an array of Event objects
     */
    public function findCreatedAfter(DateTimeImmutable $date): array
    {
        return $this->createQueryBuilder('e')
            ->andWhere('e.createdAt > :date')
            ->setParameter('date', $date)
            ->orderBy('e.createdAt', 'ASC')
            ->getQuery()
            ->getResult();
    }

    /**
     * Find events by pre event identifier
     *
     * @return Event[] Returns an array of Event objects
     */
    public function findByPreEventIdentifier(string $preEventIdentifier): array
    {
        return $this->createQueryBuilder('e')
            ->andWhere('e.preEventIdentifier = :preEventIdentifier')
            ->setParameter('preEventIdentifier', $preEventIdentifier)
            ->orderBy('e.createdAt', 'DESC')
            ->getQuery()
            ->getResult();
    }

    /**
     * Find events by follow event identifier
     *
     * @return Event[] Returns an array of Event objects
     */
    public function findByFollowEventIdentifier(string $followEventIdentifier): array
    {
        return $this->createQueryBuilder('e')
            ->andWhere('e.followEventIdentifier = :followEventIdentifier')
            ->setParameter('followEventIdentifier', $followEventIdentifier)
            ->orderBy('e.createdAt', 'DESC')
            ->getQuery()
            ->getResult();
    }
}