<?php

namespace App\Tests\Secretary;

use App\Clinic\Entity\Clinic;
use App\Doctor\Entity\Doctor;
use App\Secretary\Entity\DoctorSecretary;
use App\Secretary\Repository\DoctorSecretaryRepository;
use App\Tests\ApiTestCase;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;

/**
 * The scope key used to be (doctor_id, secretary_id, owner_type), which left
 * clinic_id out. A secretary assigned to one doctor in two clinics collided on
 * the second row because both said owner_type = 'clinic'. Phase 3 folded the
 * tenant pair into the key, so the environment is part of the identity.
 */
class SecretaryMultiClinicScopeTest extends ApiTestCase
{
    private function makeDoctor(): Doctor
    {
        $doctor = new Doctor($this->createUser(['ROLE_DOCTOR']), 'دکتر چند-کلینیک');
        $this->em->persist($doctor);
        $this->em->flush();

        return $doctor;
    }

    private function makeClinic(Doctor $doctor): Clinic
    {
        $clinic = new Clinic($this->createUser(['ROLE_CLINIC']));
        $clinic->setName('کلینیک تست منشی');
        $clinic->getDoctors()->add($doctor);
        $this->em->persist($clinic);
        $this->em->flush();

        return $clinic;
    }

    public function testSameSecretaryCanServeSameDoctorInTwoDifferentClinics(): void
    {
        $doctor    = $this->makeDoctor();
        $clinicA   = $this->makeClinic($doctor);
        $clinicB   = $this->makeClinic($doctor);
        $secretary = $this->createUser(['ROLE_SECRETARY']);

        $this->em->persist(new DoctorSecretary($doctor, $secretary, $clinicA));
        $this->em->persist(new DoctorSecretary($doctor, $secretary, $clinicB));
        $this->em->flush();

        /** @var DoctorSecretaryRepository $repo */
        $repo = $this->em->getRepository(DoctorSecretary::class);

        $inA = $repo->findActiveClinicRow($secretary, $clinicA, $doctor);
        $inB = $repo->findActiveClinicRow($secretary, $clinicB, $doctor);

        self::assertNotNull($inA, 'رابطهٔ کلینیک اول باید پیدا شود');
        self::assertNotNull($inB, 'رابطهٔ کلینیک دوم باید پیدا شود');
        self::assertNotSame($inA->getId(), $inB->getId(), 'دو ردیف مستقل، نه یک ردیف مشترک');
        self::assertSame($clinicA->getId(), $inA->getEntityId());
        self::assertSame($clinicB->getId(), $inB->getEntityId());
    }

    /** همان پزشک، همان منشی، همان کلینیک — هنوز تکراری است. */
    public function testDuplicateAssignmentInTheSameClinicIsStillRejected(): void
    {
        $doctor    = $this->makeDoctor();
        $clinic    = $this->makeClinic($doctor);
        $secretary = $this->createUser(['ROLE_SECRETARY']);

        $this->em->persist(new DoctorSecretary($doctor, $secretary, $clinic));
        $this->em->flush();

        $this->em->persist(new DoctorSecretary($doctor, $secretary, $clinic));
        $this->expectException(UniqueConstraintViolationException::class);
        $this->em->flush();
    }

    /** محیط شخصی و محیط کلینیک دو مالک متفاوت‌اند، پس هر دو کنار هم می‌نشینند. */
    public function testPersonalAndClinicAssignmentsCoexist(): void
    {
        $doctor    = $this->makeDoctor();
        $clinic    = $this->makeClinic($doctor);
        $secretary = $this->createUser(['ROLE_SECRETARY']);

        $personal = new DoctorSecretary($doctor, $secretary);
        $inClinic = new DoctorSecretary($doctor, $secretary, $clinic);
        $this->em->persist($personal);
        $this->em->persist($inClinic);
        $this->em->flush();

        self::assertSame(['doctor', $doctor->getId()], [$personal->getEntityType(), $personal->getEntityId()]);
        self::assertSame(['clinic', $clinic->getId()], [$inClinic->getEntityType(), $inClinic->getEntityId()]);
    }

    /** بدون کلینیک، محیط همان مطب شخصی است — ترکیب ناسازگار اصلاً بیان‌شدنی نیست. */
    public function testAssignmentWithoutAClinicBelongsToThePersonalPractice(): void
    {
        $doctor    = $this->makeDoctor();
        $secretary = $this->createUser(['ROLE_SECRETARY']);

        $relation = new DoctorSecretary($doctor, $secretary, null);

        self::assertSame('doctor', $relation->getEntityType());
        self::assertSame($doctor->getId(), $relation->getEntityId());
    }
}
