<?php

namespace App\Tests\Insurance;

use App\ClinicService\Entity\ServiceItem;
use App\ClinicService\Entity\ServiceSection;
use App\Doctor\Entity\Doctor;
use App\Insurance\Entity\TenantInsurance;
use App\Insurance\Entity\TenantServiceCoverage;
use App\Tests\ApiTestCase;

/**
 * The service-coverage list batch-fetches the referenced service items in one
 * query instead of find()-per-row. This guards the refactor's correctness: every
 * row must still carry the right service_item_uuid.
 */
class ServiceCoverageNPlusOneTest extends ApiTestCase
{
    public function testEveryRowResolvesItsServiceItemUuid(): void
    {
        $owner  = $this->createUser(['ROLE_DOCTOR']);
        $doctor = new Doctor($owner, 'دکتر تست');
        $this->em->persist($doctor);
        $this->em->flush();

        $tenant  = new TenantInsurance(TenantInsurance::TYPE_DOCTOR, $doctor->getId(), 1);
        $section = new ServiceSection(TenantInsurance::TYPE_DOCTOR, $doctor->getId(), 'بخش');
        $this->em->persist($tenant);
        $this->em->persist($section);
        $this->em->flush();

        $expectedUuids = [];
        for ($i = 0; $i < 4; $i++) {
            $item = new ServiceItem($section, "خدمت $i");
            $this->em->persist($item);
            $this->em->flush();
            $expectedUuids[] = $item->getUuid();
            $this->em->persist(new TenantServiceCoverage($tenant->getId(), $item->getId()));
        }
        $this->em->flush();

        $body = $this->authJson(
            'GET',
            '/api/v1/billing/tenant-insurances/' . $tenant->getUuid() . '/service-coverage',
            $owner,
        );

        $this->assertSame(200, $this->responseCode());
        $rows = $body['data']['data'] ?? $body['data'];
        $this->assertCount(4, $rows);

        $returnedUuids = array_column($rows, 'service_item_uuid');
        sort($expectedUuids);
        sort($returnedUuids);
        $this->assertSame($expectedUuids, $returnedUuids);
    }

    /** @return array{0: \App\Auth\Entity\User, 1: TenantInsurance} */
    private function makeContract(int $coverageRows): array
    {
        $owner  = $this->createUser(['ROLE_DOCTOR']);
        $doctor = new Doctor($owner, 'دکتر تست');
        $this->em->persist($doctor);
        $this->em->flush();

        $tenant  = new TenantInsurance(TenantInsurance::TYPE_DOCTOR, $doctor->getId(), 1);
        $section = new ServiceSection(TenantInsurance::TYPE_DOCTOR, $doctor->getId(), 'بخش');
        $this->em->persist($tenant);
        $this->em->persist($section);
        $this->em->flush();

        for ($i = 0; $i < $coverageRows; $i++) {
            $item = new ServiceItem($section, "خدمت $i");
            $this->em->persist($item);
            $this->em->flush();
            $this->em->persist(new TenantServiceCoverage($tenant->getId(), $item->getId()));
        }
        $this->em->flush();

        return [$owner, $tenant];
    }

    public function testQueryCountDoesNotGrowWithCoverageRows(): void
    {
        $this->client->disableReboot();

        [$ownerS, $small] = $this->makeContract(1);
        [$ownerL, $large] = $this->makeContract(6);
        $this->em->clear();

        $url = fn (TenantInsurance $t) => '/api/v1/billing/tenant-insurances/' . $t->getUuid() . '/service-coverage';

        $qSmall = $this->countQueries(fn () => $this->authJson('GET', $url($small), $ownerS));
        $qLarge = $this->countQueries(fn () => $this->authJson('GET', $url($large), $ownerL));

        // batch fetch → constant query count; per-row find() would add ~1/row.
        $this->assertLessThanOrEqual($qSmall + 1, $qLarge, "N+1: query count grew from $qSmall to $qLarge");
    }
}
