<?php

namespace App\Tests\Doctor;

use App\Clinic\Entity\Clinic;
use App\ClinicInvitation\Entity\ClinicDoctorInvitation;
use App\Doctor\Entity\Doctor;
use App\Shared\Exception\AppException;
use App\Tests\ApiTestCase;

/**
 * A doctor/clinic name reaches the public site's <title> and search results, so a
 * phone number or "test" must never be storable. The guard lives on the entity
 * because eight different call sites construct a Doctor.
 */
class PollutedNameRejectionTest extends ApiTestCase
{
    public function testDoctorCannotBeCreatedWithPhoneNumberAsName(): void
    {
        $this->expectException(AppException::class);
        new Doctor($this->createUser(['ROLE_DOCTOR']), '09390039833');
    }

    public function testDoctorCannotBeRenamedToPlaceholder(): void
    {
        $doctor = new Doctor($this->createUser(['ROLE_DOCTOR']), 'دکتر علی احمدی');

        $this->expectException(AppException::class);
        $doctor->setName('test');
    }

    public function testClinicCannotBeNamedAfterPhoneNumber(): void
    {
        $clinic = new Clinic($this->createUser(['ROLE_CLINIC']));

        $this->expectException(AppException::class);
        $clinic->setName('09398631203');
    }

    public function testClinicNameMayStayNullBeforeItIsSet(): void
    {
        $clinic = new Clinic($this->createUser(['ROLE_CLINIC']));
        $clinic->setName(null);

        $this->assertNull($clinic->getName());
    }

    public function testAdminCreatingDoctorWithPhoneNameGets422(): void
    {
        $admin = $this->createUser(['ROLE_ADMIN']);
        $this->em->flush();

        $this->authJson('POST', '/api/v1/admin/doctors', $admin, [
            'name'          => '09390039833',
            'mobile_number' => '0912' . random_int(1000000, 9999999),
        ]);

        $this->assertSame(422, $this->responseCode());
    }

    /**
     * ریشهٔ آلودگی تولیدی: دعوت پزشک فقط با موبایل، شماره را به‌عنوان نام می‌نشاند.
     */
    public function testInvitingDoctorByMobileDoesNotUseMobileAsName(): void
    {
        $owner  = $this->createUser(['ROLE_CLINIC']);
        $clinic = new Clinic($owner);
        $this->em->persist($clinic);
        $this->em->flush();

        $mobile = '0912' . random_int(1000000, 9999999);
        $this->authJson('POST', "/api/v1/admin/clinic/{$clinic->getUuid()}/invite-doctor", $owner, [
            'mobile' => $mobile,
        ]);
        $this->assertSame(201, $this->responseCode());

        $invitation = $this->em->getRepository(ClinicDoctorInvitation::class)
            ->findOneBy(['mobile' => $mobile]);
        $this->assertNotNull($invitation, 'invitation was not created');

        $this->client->request('POST', "/api/v1/clinic-invitation/{$invitation->getToken()}/accept");
        $this->assertSame(200, $this->responseCode());

        $this->em->clear();
        $doctor = $this->em->getRepository(Doctor::class)->findOneBy(['mobileNumber' => $mobile]);

        $this->assertNotNull($doctor, 'invited doctor was not created');
        $this->assertNotSame($mobile, $doctor->getName(), 'mobile number leaked into the doctor name');
        $this->assertSame('پزشک دعوت‌شده', $doctor->getName());
    }

    public function testInvitedNameIsUsedWhenTheClinicProvidesOne(): void
    {
        $owner  = $this->createUser(['ROLE_CLINIC']);
        $clinic = new Clinic($owner);
        $this->em->persist($clinic);
        $this->em->flush();

        $mobile = '0912' . random_int(1000000, 9999999);
        $this->authJson('POST', "/api/v1/admin/clinic/{$clinic->getUuid()}/invite-doctor", $owner, [
            'mobile' => $mobile,
            'name'   => 'دکتر مریم رضایی',
        ]);
        $this->assertSame(201, $this->responseCode());

        $invitation = $this->em->getRepository(ClinicDoctorInvitation::class)
            ->findOneBy(['mobile' => $mobile]);
        $this->client->request('POST', "/api/v1/clinic-invitation/{$invitation->getToken()}/accept");
        $this->assertSame(200, $this->responseCode());

        $this->em->clear();
        $doctor = $this->em->getRepository(Doctor::class)->findOneBy(['mobileNumber' => $mobile]);
        $this->assertSame('دکتر مریم رضایی', $doctor->getName());
    }
}
