<?php

declare(strict_types=1);

namespace App\Tests\Module\Catalog\Api;

use DateTimeImmutable;

/**
 * Tests RG-1.08 / RG-1.09 / RG-1.10 : comportement de GET /api/categories.
 *
 *  - RG-1.08 : par defaut, les categories soft-deleted sont exclues ;
 *  - RG-1.09 : `?includeDeleted=true` inclut les soft-deleted ;
 *  - RG-1.10 : tri par defaut `name ASC` cote serveur.
 *
 * @internal
 */
final class CategoryListTest extends AbstractCatalogApiTestCase
{
    public function testListExcludesSoftDeletedByDefault(): void
    {
        $type = $this->createCategoryType();
        $this->createCategory(self::TEST_CATEGORY_PREFIX.'alpha', $type);
        $this->createCategory(self::TEST_CATEGORY_PREFIX.'beta', $type);
        $this->createCategory(
            self::TEST_CATEGORY_PREFIX.'gone',
            $type,
            new DateTimeImmutable(),
        );

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

        $data    = $response->toArray();
        $members = $data['member'];

        // On filtre sur le prefix test_cat_ pour ne pas etre pollue par
        // d'autres entrees presentes en base (fixtures, autres tests).
        $names = array_values(array_filter(
            array_map(fn (array $m): string => $m['name'], $members),
            fn (string $n): bool => str_starts_with($n, self::TEST_CATEGORY_PREFIX),
        ));

        self::assertContains(self::TEST_CATEGORY_PREFIX.'alpha', $names);
        self::assertContains(self::TEST_CATEGORY_PREFIX.'beta', $names);
        self::assertNotContains(
            self::TEST_CATEGORY_PREFIX.'gone',
            $names,
            'Les categories soft-deleted doivent etre exclues par defaut (RG-1.08).',
        );
    }

    public function testIncludeDeletedFlagSurfacesSoftDeleted(): void
    {
        $type = $this->createCategoryType();
        $this->createCategory(self::TEST_CATEGORY_PREFIX.'alpha2', $type);
        $this->createCategory(
            self::TEST_CATEGORY_PREFIX.'gone2',
            $type,
            new DateTimeImmutable(),
        );

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

        $names = array_values(array_filter(
            array_map(fn (array $m): string => $m['name'], $response->toArray()['member']),
            fn (string $n): bool => str_starts_with($n, self::TEST_CATEGORY_PREFIX),
        ));

        self::assertContains(self::TEST_CATEGORY_PREFIX.'alpha2', $names);
        self::assertContains(
            self::TEST_CATEGORY_PREFIX.'gone2',
            $names,
            '?includeDeleted=true doit faire apparaitre les soft-deleted (RG-1.09).',
        );
    }

    public function testDefaultSortIsNameAsc(): void
    {
        $type = $this->createCategoryType();
        // Insertion volontairement dans le desordre pour prouver le tri.
        $this->createCategory(self::TEST_CATEGORY_PREFIX.'zorro', $type);
        $this->createCategory(self::TEST_CATEGORY_PREFIX.'alpha_sort', $type);
        $this->createCategory(self::TEST_CATEGORY_PREFIX.'mid', $type);

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

        $names = array_values(array_filter(
            array_map(fn (array $m): string => $m['name'], $response->toArray()['member']),
            fn (string $n): bool => str_starts_with($n, self::TEST_CATEGORY_PREFIX),
        ));

        // Verifie que la sous-liste de nos 3 entrees est triee croissante.
        $expectedSubset = [
            self::TEST_CATEGORY_PREFIX.'alpha_sort',
            self::TEST_CATEGORY_PREFIX.'mid',
            self::TEST_CATEGORY_PREFIX.'zorro',
        ];

        $filtered = array_values(array_intersect($names, $expectedSubset));
        self::assertSame(
            $expectedSubset,
            $filtered,
            'Les categories doivent etre retournees triees par name ASC (RG-1.10).',
        );
    }
}
