<?php

namespace App\Waitlist\Service;

use App\Appointment\Entity\Appointment;
use App\Patient\Repository\PatientRecordRepository;
use App\Waitlist\Entity\WaitlistEntry;
use App\Waitlist\Repository\WaitlistEntryRepository;
use Doctrine\ORM\EntityManagerInterface;

/**
 * بستن ردیف انتظار وقتی همان بیمار همان سرویس را رزرو کرد.
 *
 * تطبیق عمداً **تنگ** است: همان بیمار، همان سرویس، و زمان نوبت داخل بازهٔ خواسته‌شده.
 * تطبیق شل («هر انتظاری از این بیمار») ردیفی را می‌بندد که برای خدمت دیگری بود و بیمار
 * هنوز منتظرش است — و او دیگر هرگز خبر نمی‌شود.
 */
final class WaitlistConverter
{
    public function __construct(
        private readonly WaitlistEntryRepository $entries,
        private readonly PatientRecordRepository $patients,
        private readonly EntityManagerInterface  $em,
    ) {}

    /**
     * @return int تعداد ردیف‌هایی که بسته شد
     */
    public function convertFor(Appointment $appointment): int
    {
        $service = $appointment->getServiceItem();

        if ($service === null) {
            return 0;
        }

        $patient = $this->patients->findOneBy([
            'user'       => $appointment->getUser(),
            'entityType' => $appointment->getEntityType(),
            'entityId'   => $appointment->getEntityId(),
        ]);

        if ($patient === null) {
            return 0;
        }

        $converted = 0;

        foreach ($this->entries->findForPatient($patient) as $entry) {
            // ردیفِ بسته دوباره بسته نمی‌شود — همین idempotency تحویل دوبارهٔ پیام است.
            if (!in_array($entry->getStatus(), [WaitlistEntry::STATUS_WAITING, WaitlistEntry::STATUS_NOTIFIED], true)) {
                continue;
            }

            if ($entry->getServiceItem()->getId() !== $service->getId()) {
                continue;
            }

            if (!$entry->covers($appointment->getSlotStart())) {
                continue;
            }

            $entry->markConverted($appointment);
            $converted++;
        }

        if ($converted > 0) {
            $this->em->flush();
        }

        return $converted;
    }
}
