<?php

namespace App\Package\Service;

use App\Appointment\Entity\Appointment;
use App\ClinicService\Entity\ServiceItem;
use App\Package\Entity\PatientPackage;
use App\Package\Repository\PatientPackageRepository;
use App\Patient\Entity\PatientRecord;
use App\Patient\Repository\PatientRecordRepository;

/**
 * پیدا کردن پکیج قابل استفاده و مصرفش هنگام ثبت نوبت.
 *
 * ⚠️ تفکیک حیاتی: `quote` هیچ‌وقت مصرف نمی‌کند، فقط **می‌گوید** که مصرف خواهد شد.
 * اگر پیش‌نمایش مصرف می‌کرد، هر رفرش صفحه یک جلسه از بیمار می‌گرفت.
 */
final class PackageConsumptionService
{
    public function __construct(
        private readonly PatientPackageRepository $patientPackages,
        private readonly PatientRecordRepository  $patients,
        private readonly CreditLedgerService      $ledger,
    ) {}

    /** قدیمی‌ترین پکیج معتبر با ماندهٔ مثبت (FIFO). */
    public function firstUsable(PatientRecord $patient, ServiceItem $service, ?int $at = null): ?PatientPackage
    {
        $at = $at ?? time();

        foreach ($this->patientPackages->findUsable($patient, $service, $at) as $candidate) {
            if ($this->ledger->balance($candidate) > 0) {
                return $candidate;
            }
        }

        return null;
    }

    /**
     * پروندهٔ بیمار در همین محیط — پکیج کلینیک الف در کلینیک ب معنا ندارد.
     */
    public function patientRecordFor(Appointment $appointment): ?PatientRecord
    {
        return $this->patients->findOneBy([
            'user'       => $appointment->getUser(),
            'entityType' => $appointment->getEntityType(),
            'entityId'   => $appointment->getEntityId(),
        ]);
    }

    /**
     * مصرف واقعی هنگام ثبت نهایی.
     *
     * @return bool `true` یعنی یک جلسه کسر شد
     */
    public function consumeFor(Appointment $appointment): bool
    {
        $service = $appointment->getServiceItem();
        $patient = $service === null ? null : $this->patientRecordFor($appointment);

        if ($service === null || $patient === null) {
            return false;
        }

        $package = $this->firstUsable($patient, $service, $appointment->getSlotStart());

        if ($package === null) {
            return false;
        }

        return $this->ledger->consume($package, $appointment, $service);
    }
}
