<?php

namespace App\Package\Service;

use App\Auth\Entity\User;
use App\Package\Entity\Package;
use App\Package\Entity\PatientPackage;
use App\Package\Entity\SessionCreditLedger;
use App\Package\Repository\PatientPackageRepository;
use App\Patient\Entity\PatientRecord;
use App\Shared\Constant\ErrorCodes;
use App\Shared\Event\DomainEventPublisher;
use App\Shared\Event\DomainEvents;
use App\Shared\Exception\AppException;

/**
 * فروش پکیج به بیمار.
 *
 * خرید و ردیف `purchase` یک عمل‌اند: پکیجی که بدون ردیف دفتر ثبت شود مانده‌اش صفر
 * است و بیمار پولش را داده ولی چیزی نگرفته.
 */
final class PackageSalesService
{
    public function __construct(
        private readonly PatientPackageRepository $patientPackages,
        private readonly CreditLedgerService      $ledger,
        private readonly DomainEventPublisher     $events,
    ) {}

    public function sell(Package $package, PatientRecord $patient, ?User $by = null, ?int $pricePaid = null): PatientPackage
    {
        if (!$package->isActive()) {
            throw new AppException(ErrorCodes::ERR_VALIDATION_001, 'این پکیج غیرفعال است', 422, 'package_uuid');
        }

        if ($package->getServices()->isEmpty()) {
            throw new AppException(ErrorCodes::ERR_VALIDATION_001, 'پکیج بدون سرویس قابل فروش نیست', 422, 'services');
        }

        if ($patient->getEntityType() !== $package->getEntityType() || $patient->getEntityId() !== $package->getEntityId()) {
            throw new AppException(ErrorCodes::ERR_NOT_FOUND_001, 'بیمار یافت نشد', 404);
        }

        $sold = new PatientPackage($package, $patient);

        if ($pricePaid !== null) {
            $sold->setPricePaidRials($pricePaid);
        }

        $this->patientPackages->save($sold);

        $this->ledger->record(
            $sold,
            SessionCreditLedger::KIND_PURCHASE,
            $sold->getSessionCount(),
            reason: sprintf('خرید پکیج «%s»', $package->getName()),
            by: $by,
        );

        $this->events->recordAndFlush(
            $sold->getEntityType(),
            $sold->getEntityId(),
            DomainEvents::PACKAGE_PURCHASED,
            [
                'patient_package_uuid' => $sold->getUuid(),
                'package_uuid'         => $package->getUuid(),
                'session_count'        => $sold->getSessionCount(),
            ],
        );

        return $sold;
    }
}
