<?php

declare(strict_types=1);

namespace App\Tests\Module\Catalog\Api;

use App\Module\Catalog\Domain\Entity\CategoryType;

/**
 * Tests du seed de la taxonomie PRESTATAIRE (M3 1.1) cote API.
 *
 * Le multi-select « Categorie » du prestataire (formulaire principal + adresse)
 * consomme `GET /api/categories?typeCode=PRESTATAIRE`. Ce test prouve que :
 *  - le filtre `?typeCode=PRESTATAIRE` ne renvoie QUE les categories du type
 *    PRESTATAIRE (aucune fuite de categorie d'un autre type) ;
 *  - chaque membre renvoye porte bien le type PRESTATAIRE dans `categoryTypes`.
 *
 * NB : la base de test est purgee de toute categorie / type entre chaque test
 * (cf. AbstractCatalogApiTestCase::cleanupCatalogTestData), donc le type et les
 * categories PRESTATAIRE sont materialises ici (et non lus depuis le seed de la
 * migration / fixture, qui ne survit pas a la purge). On valide ainsi le contrat
 * du filtre sur le code reel `PRESTATAIRE`. La presence du seed apres un
 * `make db-reset` reel est, elle, verifiee par l'idempotence des fixtures.
 *
 * @internal
 */
final class CategoryPrestataireSeedTest extends AbstractCatalogApiTestCase
{
    /**
     * Categories de demonstration seedees par la migration / fixture PRESTATAIRE.
     */
    private const array PROVIDER_CATEGORIES = [
        'Maintenance industrielle',
        'Nettoyage',
        'Transport',
    ];

    public function testTypeCodePrestataireReturnsOnlyProviderCategories(): void
    {
        $providerType = $this->getOrCreatePrestataireType();
        foreach (self::PROVIDER_CATEGORIES as $name) {
            $this->createCategory($name, $providerType);
        }

        // Bruit : un type + une categorie d'un autre type ne doivent PAS fuiter.
        $noiseType = $this->createCategoryType('TEST_FOURNISSEUR', 'Test Fournisseur');
        $this->createCategory(self::TEST_CATEGORY_PREFIX.'noise', $noiseType);

        $client   = $this->createAdminClient();
        $response = $client->request('GET', '/api/categories?typeCode=PRESTATAIRE&pagination=false');
        self::assertSame(200, $response->getStatusCode());

        $members = $response->toArray()['member'];
        $names   = array_map(static fn (array $m): string => $m['name'], $members);
        sort($names);

        $expected = self::PROVIDER_CATEGORIES;
        sort($expected);
        self::assertSame(
            $expected,
            $names,
            'Le filtre ?typeCode=PRESTATAIRE doit ne renvoyer QUE les categories du type PRESTATAIRE.',
        );

        // Chaque categorie remontee doit PORTER le type PRESTATAIRE.
        foreach ($members as $member) {
            self::assertContains('PRESTATAIRE', array_column($member['categoryTypes'], 'code'));
        }
    }

    public function testTypeCodePrestataireKeepsHydraPagination(): void
    {
        $providerType = $this->getOrCreatePrestataireType();
        $this->createCategory('Maintenance industrielle', $providerType);

        $client   = $this->createAdminClient();
        $response = $client->request('GET', '/api/categories?typeCode=PRESTATAIRE');
        self::assertSame(200, $response->getStatusCode());

        $data = $response->toArray();
        self::assertArrayHasKey('totalItems', $data, 'Le filtre ne doit pas casser la pagination Hydra.');
        self::assertArrayHasKey('member', $data);

        foreach ($data['member'] as $member) {
            self::assertContains('PRESTATAIRE', array_column($member['categoryTypes'], 'code'));
        }
    }

    /**
     * Recupere le type PRESTATAIRE reel, ou le cree s'il est absent. Le code
     * `PRESTATAIRE` est seede par CategoryTypeFixtures (present en debut de suite),
     * mais le cleanup purge tous les `category_type` entre les tests : selon
     * l'ordre d'execution, le type peut donc exister ou non. Le get-or-create rend
     * le test robuste sans dependre du seed ni le dupliquer.
     */
    private function getOrCreatePrestataireType(): CategoryType
    {
        $em       = $this->getEm();
        $existing = $em->getRepository(CategoryType::class)->findOneBy(['code' => 'PRESTATAIRE']);

        if ($existing instanceof CategoryType) {
            return $existing;
        }

        return $this->createCategoryType('PRESTATAIRE', 'Prestataire');
    }
}
