<?php

namespace App\Waitlist\Repository;

use App\ClinicService\Entity\ServiceItem;
use App\Patient\Entity\PatientRecord;
use App\Waitlist\Entity\WaitlistEntry;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;

/** @extends ServiceEntityRepository<WaitlistEntry> */
class WaitlistEntryRepository extends ServiceEntityRepository
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, WaitlistEntry::class);
    }

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

    /**
     * چه کسانی منتظر این سرویس در این لحظه‌اند؟ — کوئری داغِ لحظهٔ لغو.
     *
     * شعبهٔ تهی یعنی «هر شعبه»؛ کسی که شعبه مشخص کرده فقط برای همان شعبه خبر می‌شود.
     *
     * @return WaitlistEntry[] مرتب بر اساس اولویت، بعد قدمت
     */
    public function findMatching(ServiceItem $service, int $start, ?int $branchId, ?int $now = null): array
    {
        $now = $now ?? time();

        $qb = $this->createQueryBuilder('w')
            ->where('w.serviceItem = :service')
            ->andWhere('w.status IN (:open)')
            ->andWhere('w.desiredFrom <= :start')
            ->andWhere('w.desiredTo >= :start')
            ->andWhere('w.desiredTo >= :now')
            ->andWhere('w.notifyCount < :maxNotifications')
            ->setParameter('service', $service)
            ->setParameter('open', [WaitlistEntry::STATUS_WAITING, WaitlistEntry::STATUS_NOTIFIED])
            ->setParameter('start', $start)
            ->setParameter('now', $now)
            ->setParameter('maxNotifications', WaitlistEntry::MAX_NOTIFICATIONS)
            ->orderBy('w.priority', 'DESC')
            ->addOrderBy('w.createdAt', 'ASC');

        // شعبهٔ تهی روی خودِ ردیف یعنی «هر شعبه»؛ پس وقتی ظرفیت یک شعبهٔ مشخص آزاد
        // می‌شود، هم بی‌قیدها خبر می‌شوند هم آن‌هایی که همان شعبه را خواسته‌اند.
        if ($branchId !== null) {
            $qb->andWhere('w.branchId IS NULL OR w.branchId = :branch')
                ->setParameter('branch', $branchId);
        }

        return $qb->getQuery()->getResult();
    }

    /** @return WaitlistEntry[] */
    public function findForPair(string $entityType, int $entityId, ?string $status = null): array
    {
        $qb = $this->createQueryBuilder('w')
            ->where('w.entityType = :type')
            ->andWhere('w.entityId = :id')
            ->setParameter('type', $entityType)
            ->setParameter('id', $entityId)
            ->orderBy('w.priority', 'DESC')
            ->addOrderBy('w.createdAt', 'DESC');

        if ($status !== null) {
            $qb->andWhere('w.status = :status')->setParameter('status', $status);
        }

        return $qb->getQuery()->getResult();
    }

    /** @return WaitlistEntry[] */
    public function findForPatient(PatientRecord $patient): array
    {
        return $this->findBy(['patientRecord' => $patient], ['createdAt' => 'DESC']);
    }

    public function save(WaitlistEntry $entry, bool $flush = true): void
    {
        $this->getEntityManager()->persist($entry);

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