<?php

namespace App\Tests\Insurance;

use App\Clinic\Entity\Clinic;
use App\Doctor\Entity\Doctor;
use App\Insurance\Entity\Insurance;
use App\Insurance\Enum\InsuranceType;
use App\Tests\ApiTestCase;
use Symfony\Component\Uid\Uuid;

/**
 * درصد و شرایط هر بیمه می‌تواند برای هر پزشک متفاوت باشد؛ در کلینیک چندپزشکه قرارداد
 * بیمه به‌ازای پزشک (`doctor_uuid`) ذخیره می‌شود، نه یک‌بار در سطح کلینیک. این تست
 * هدف‌گیری per-doctor روی اندپوینت‌های tenant-insurances را پوشش می‌دهد.
 */
class TenantInsurancePerDoctorTest extends ApiTestCase
{
    private function makeDoctor(string $name): Doctor
    {
        $user   = $this->createUser(['ROLE_USER', 'ROLE_DOCTOR']);
        $doctor = new Doctor($user, $name);
        $doctor->setMobileNumber($user->getMobileNumber());
        $this->em->persist($doctor);
        $this->em->flush();

        return $doctor;
    }

    /** @return array{0: \App\Auth\Entity\User, 1: Clinic} */
    private function makeClinicWith(Doctor ...$doctors): array
    {
        $owner  = $this->createUser(['ROLE_USER', 'ROLE_CLINIC']);
        $clinic = new Clinic($owner);
        $clinic->setName('کلینیک تست بیمه');
        foreach ($doctors as $d) {
            $clinic->getDoctors()->add($d);
        }
        $this->em->persist($clinic);
        $this->em->flush();

        return [$owner, $clinic];
    }

    private function makeInsurance(InsuranceType $type = InsuranceType::Basic): Insurance
    {
        $insurance = new Insurance('بیمه ' . random_int(1000, 9999), $type);
        $this->em->persist($insurance);
        $this->em->flush();

        return $insurance;
    }

    public function testClinicOwnerCreatesContractForMemberDoctor(): void
    {
        $doctor           = $this->makeDoctor('دکتر عضو');
        [$owner, $clinic] = $this->makeClinicWith($doctor);
        $insurance        = $this->makeInsurance();

        $body = $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
            'doctor_uuid'      => $doctor->getUuid(),
            'insurance_id'     => $insurance->getId(),
            'coverage_percent' => 80,
        ]);

        self::assertSame(201, $this->responseCode());
        self::assertSame('doctor', $body['data']['data']['entity_type']);
        self::assertSame($doctor->getId(), $body['data']['data']['entity_id']);
    }

    public function testContractsAreIsolatedPerDoctor(): void
    {
        $first            = $this->makeDoctor('دکتر اول');
        $second           = $this->makeDoctor('دکتر دوم');
        [$owner, $clinic] = $this->makeClinicWith($first, $second);
        $insA             = $this->makeInsurance();
        $insB             = $this->makeInsurance();

        $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
            'doctor_uuid' => $first->getUuid(), 'insurance_id' => $insA->getId(), 'coverage_percent' => 70,
        ]);
        $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
            'doctor_uuid' => $second->getUuid(), 'insurance_id' => $insB->getId(), 'coverage_percent' => 40,
        ]);

        $body = $this->authJson('GET', "/api/v1/billing/tenant-insurances?doctor_uuid={$first->getUuid()}", $owner);
        self::assertSame(200, $this->responseCode());

        $insuranceIds = array_map(fn ($r) => $r['insurance_id'], $body['data']['data']);
        self::assertContains($insA->getId(), $insuranceIds, 'قرارداد پزشک اول باید دیده شود');
        self::assertNotContains($insB->getId(), $insuranceIds, 'قرارداد پزشک دوم نباید در فهرست پزشک اول باشد');
    }

    public function testStrangerDoctorUuidIsForbidden(): void
    {
        $member          = $this->makeDoctor('دکتر عضو');
        $outsider        = $this->makeDoctor('دکتر بیرونی');
        [$owner, $clinic] = $this->makeClinicWith($member);
        $insurance       = $this->makeInsurance();

        $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
            'doctor_uuid'      => $outsider->getUuid(),
            'insurance_id'     => $insurance->getId(),
            'coverage_percent' => 50,
        ]);

        self::assertSame(403, $this->responseCode(), 'پزشکِ خارج از کلینیک قابل تنظیم نیست');
    }

    public function testUnknownDoctorUuidReturns404(): void
    {
        [$owner] = $this->makeClinicWith($this->makeDoctor('دکتر عضو'));

        $this->authJson('GET', '/api/v1/billing/tenant-insurances?doctor_uuid=' . Uuid::v4()->toRfc4122(), $owner);

        self::assertSame(404, $this->responseCode());
    }

    public function testWithoutDoctorUuidKeepsLegacyBehavior(): void
    {
        $doctor    = $this->makeDoctor('دکتر مستقل');
        $insurance = $this->makeInsurance();

        $body = $this->authJson('POST', '/api/v1/billing/tenant-insurances', $doctor->getUser(), [
            'insurance_id'     => $insurance->getId(),
            'coverage_percent' => 60,
        ]);

        self::assertSame(201, $this->responseCode());
        self::assertSame('doctor', $body['data']['data']['entity_type']);
        self::assertSame($doctor->getId(), $body['data']['data']['entity_id']);
    }
}
