<?php

namespace App\Shared\Tenant;

use App\Shared\Context\EntityContext;
use Doctrine\ORM\Mapping as ORM;

/**
 * جفت مالکیتِ محیط — همان قراردادی که ServiceSection و PatientRecord از قبل دارند:
 * entity_type ∈ {doctor, clinic} به‌همراه شناسهٔ همان موجودیت.
 *
 * مقدارها فقط از EntityContext::toEntityPair() می‌آیند تا «کدام محیط» یک منبع
 * حقیقت بیشتر نداشته باشد ({@see \App\Shared\Context\EntityContextResolver}).
 *
 * هیچ‌کدام از دو ستون مقدار پیش‌فرض ندارند: اگر سازنده assignTenant() را فراموش
 * کند، flush با خطای «typed property must not be accessed before initialization»
 * می‌شکند. این عمدی است — ردیفِ بی‌محیط بی‌صدا از دید همه پنهان می‌شود.
 *
 * طول ۱۰ با service_sections، patient_records و clinic_staff یکی است تا JOIN بین
 * جدول‌ها به collation mismatch نخورد.
 */
trait TenantOwnedTrait
{
    #[ORM\Column(name: 'entity_type', type: 'string', length: 10)]
    private string $entityType;

    #[ORM\Column(name: 'entity_id', type: 'integer')]
    private int $entityId;

    public function getEntityType(): string { return $this->entityType; }

    public function getEntityId(): int { return $this->entityId; }

    /** @throws \InvalidArgumentException اگر محیط حل نشده باشد */
    public function assignTenant(EntityContext $context): void
    {
        if (!$context->isResolved()) {
            throw new \InvalidArgumentException(sprintf(
                'Cannot assign an unresolved tenant context to %s.',
                static::class,
            ));
        }

        [$this->entityType, $this->entityId] = $context->toEntityPair();
    }

    /**
     * برای فراخوانی‌هایی که جفت را از قبل حل کرده‌اند و موجودیت را در دست ندارند —
     * مثل DiscountController که owner را به‌صورت اسکالر از resolveOwner می‌گیرد.
     * ساختن EntityContext از روی اسکالر ممکن نیست: چنین contextی isClinic() درست
     * می‌دهد ولی ->clinic تهی دارد و مصرف‌کننده را بی‌صدا می‌شکند.
     *
     * @throws \InvalidArgumentException اگر جفت معتبر نباشد
     */
    public function assignTenantPair(string $entityType, int $entityId): void
    {
        if (!in_array($entityType, [EntityContext::TYPE_DOCTOR, EntityContext::TYPE_CLINIC], true) || $entityId <= 0) {
            throw new \InvalidArgumentException(sprintf(
                'Invalid tenant pair (%s, %d) for %s.',
                $entityType,
                $entityId,
                static::class,
            ));
        }

        $this->entityType = $entityType;
        $this->entityId   = $entityId;
    }
}
