<?php

declare(strict_types=1);

namespace App\Tests\Module\Catalog\Api;

use PHPUnit\Framework\Attributes\DataProvider;

/**
 * Tests RG-1.01 : permissions RBAC catalog.categories.view / manage.
 *
 * Verifie que :
 *  - les 4 personas metier MALIO (Bureau / Compta / Commerciale / Usine) sans
 *    permission catalog.categories.* obtiennent 403 sur tous les verbes des
 *    endpoints `/api/categories*` et `/api/category_types*` ;
 *  - un utilisateur anonyme (sans JWT) obtient 401 ;
 *  - l'admin (bypass via isAdmin) obtient le code attendu (200 / 201 / 204).
 *
 * @internal
 */
final class CategoryPermissionsTest extends AbstractCatalogApiTestCase
{
    // ============ /api/categories — collection ============

    #[DataProvider('personaProvider')]
    public function testPersonaWithoutCatalogPermissionGets403OnGetCollection(string $personaLabel): void
    {
        $client = $this->createPersonaClient($personaLabel);
        $client->request('GET', '/api/categories');

        self::assertResponseStatusCodeSame(403);
    }

    public function testAnonymousGets401OnGetCollection(): void
    {
        $client = self::createClient();
        $client->request('GET', '/api/categories');

        self::assertResponseStatusCodeSame(401);
    }

    public function testAdminGets200OnGetCollection(): void
    {
        $client = $this->createAdminClient();
        $client->request('GET', '/api/categories');

        self::assertResponseStatusCodeSame(200);
    }

    public function testUserWithViewPermissionGets200OnGetCollection(): void
    {
        $client = $this->createViewClient();
        $client->request('GET', '/api/categories');

        self::assertResponseStatusCodeSame(200);
    }

    // ============ /api/categories — POST ============

    #[DataProvider('personaProvider')]
    public function testPersonaWithoutManagePermissionGets403OnPost(string $personaLabel): void
    {
        $type   = $this->createCategoryType();
        $client = $this->createPersonaClient($personaLabel);
        $client->request('POST', '/api/categories', [
            'headers' => ['Content-Type' => 'application/ld+json'],
            'json'    => [
                'name'         => self::TEST_CATEGORY_PREFIX.'forbidden',
                'categoryTypes' => ['/api/category_types/'.$type->getId()],
            ],
        ]);

        self::assertResponseStatusCodeSame(403);
    }

    public function testAnonymousGets401OnPost(): void
    {
        $type   = $this->createCategoryType();
        $client = self::createClient();
        $client->request('POST', '/api/categories', [
            'headers' => ['Content-Type' => 'application/ld+json'],
            'json'    => [
                'name'         => self::TEST_CATEGORY_PREFIX.'anon',
                'categoryTypes' => ['/api/category_types/'.$type->getId()],
            ],
        ]);

        self::assertResponseStatusCodeSame(401);
    }

    public function testAdminGets201OnPost(): void
    {
        $type   = $this->createCategoryType();
        $client = $this->createAdminClient();
        $client->request('POST', '/api/categories', [
            'headers' => ['Content-Type' => 'application/ld+json'],
            'json'    => [
                'name'         => self::TEST_CATEGORY_PREFIX.'admin_create',
                'categoryTypes' => ['/api/category_types/'.$type->getId()],
            ],
        ]);

        self::assertResponseStatusCodeSame(201);
    }

    public function testUserWithOnlyViewPermissionGets403OnPost(): void
    {
        // Prouve qu'avoir `view` ne suffit pas a POSTer (manage requis).
        $type   = $this->createCategoryType();
        $client = $this->createViewClient();
        $client->request('POST', '/api/categories', [
            'headers' => ['Content-Type' => 'application/ld+json'],
            'json'    => [
                'name'         => self::TEST_CATEGORY_PREFIX.'view_only',
                'categoryTypes' => ['/api/category_types/'.$type->getId()],
            ],
        ]);

        self::assertResponseStatusCodeSame(403);
    }

    // ============ /api/categories/{id} — PATCH ============

    #[DataProvider('personaProvider')]
    public function testPersonaWithoutManagePermissionGets403OnPatch(string $personaLabel): void
    {
        $category = $this->createCategory();
        $client   = $this->createPersonaClient($personaLabel);
        $client->request('PATCH', '/api/categories/'.$category->getId(), [
            'headers' => ['Content-Type' => 'application/merge-patch+json'],
            'json'    => ['name' => self::TEST_CATEGORY_PREFIX.'patched'],
        ]);

        self::assertResponseStatusCodeSame(403);
    }

    // ============ /api/categories/{id} — DELETE ============

    #[DataProvider('personaProvider')]
    public function testPersonaWithoutManagePermissionGets403OnDelete(string $personaLabel): void
    {
        $category = $this->createCategory();
        $client   = $this->createPersonaClient($personaLabel);
        $client->request('DELETE', '/api/categories/'.$category->getId());

        self::assertResponseStatusCodeSame(403);
    }

    public function testAdminGets204OnDelete(): void
    {
        $category = $this->createCategory();
        $client   = $this->createAdminClient();
        $client->request('DELETE', '/api/categories/'.$category->getId());

        self::assertResponseStatusCodeSame(204);
    }

    // ============ /api/category_types — referentiel ============

    #[DataProvider('personaProvider')]
    public function testPersonaWithoutCatalogPermissionGets403OnCategoryTypes(string $personaLabel): void
    {
        $client = $this->createPersonaClient($personaLabel);
        $client->request('GET', '/api/category_types');

        self::assertResponseStatusCodeSame(403);
    }

    /**
     * @return iterable<string, array{string}>
     */
    public static function personaProvider(): iterable
    {
        yield 'Bureau' => ['Bureau'];

        yield 'Compta' => ['Compta'];

        yield 'Commerciale' => ['Commerciale'];

        yield 'Usine' => ['Usine'];
    }

    public function testAnonymousGets401OnCategoryTypes(): void
    {
        $client = self::createClient();
        $client->request('GET', '/api/category_types');

        self::assertResponseStatusCodeSame(401);
    }

    public function testAdminGets200OnCategoryTypes(): void
    {
        $client = $this->createAdminClient();
        $client->request('GET', '/api/category_types');

        self::assertResponseStatusCodeSame(200);
    }

    public function testUserWithViewPermissionGets200OnCategoryTypes(): void
    {
        // Le referentiel reutilise la meme permission catalog.categories.view.
        $client = $this->createViewClient();
        $client->request('GET', '/api/category_types');

        self::assertResponseStatusCodeSame(200);
    }
}
