<?php

declare(strict_types=1);

namespace App\Tests\Module\Transport\Api;

use ApiPlatform\Symfony\Bundle\Test\Client;
use App\Module\Core\Infrastructure\DataFixtures\RbacDemoFixtures;
use DateTimeImmutable;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\NullOutput;

/**
 * Endpoint de recherche du referentiel QUALIMAT (spec-back M4 § 4.7 / RG-4.01,
 * ERP-156). Saisie assistee du nom : GET /api/qualimat_carriers?search= .
 *
 * Contrat verifie :
 *  - recherche fuzzy sur name (+ siret), SEULEMENT les lignes actives ;
 *  - tri name ASC ;
 *  - enveloppe Hydra paginee (member / totalItems / view — regle n°13) ;
 *  - 403 sans la permission transport.carriers.view (compta/usine, matrice § 5.2).
 *
 * @internal
 */
final class QualimatCarrierSearchTest extends AbstractCarrierApiTestCase
{
    private const string PWD = RbacDemoFixtures::DEMO_PASSWORD;

    /** Prefixe SIRET dedie (purge par AbstractCarrierApiTestCase::tearDown). */
    private const string SIRET_PREFIX = 'TESTQ';

    protected function setUp(): void
    {
        parent::setUp();

        // Seed idempotent des roles + matrice § 5.2 + comptes demo (meme chemin
        // qu'en recette), requis pour le test de permission (usine sans acces).
        self::bootKernel();
        $application = new Application(self::$kernel);
        $application->setAutoExit(false);
        $exit = $application->run(
            new ArrayInput([
                'command'           => 'app:seed-rbac',
                '--with-demo-users' => true,
                '--password'        => self::PWD,
            ]),
            new NullOutput(),
        );
        self::assertSame(0, $exit, 'app:seed-rbac a echoue (permissions transport.carriers.* synchronisees ?).');

        self::ensureKernelShutdown();
    }

    public function testSearchReturnsOnlyActiveOrderedByName(): void
    {
        // Marqueur unique partage par les 3 lignes : isole la recherche d'eventuelles
        // autres lignes du referentiel.
        $this->insertQualimat('QSEARCH GAMMA', true, 'A1');
        $this->insertQualimat('QSEARCH ALPHA', true, 'A2');
        $this->insertQualimat('QSEARCH BETA', false, 'A3'); // inactive -> exclue

        $client = $this->createAdminClient();
        $client->request('GET', '/api/qualimat_carriers?search=qsearch', ['headers' => ['Accept' => self::LD]]);
        self::assertResponseIsSuccessful();

        $data = $client->getResponse()->toArray();
        $names = array_column($data['member'], 'name');

        self::assertSame(2, $data['totalItems'], 'Seules les 2 lignes actives doivent remonter (BETA inactive exclue).');
        self::assertSame(['QSEARCH ALPHA', 'QSEARCH GAMMA'], $names, 'Tri name ASC, sans la ligne inactive.');
    }

    public function testSearchMatchesSiret(): void
    {
        // Le nom ne porte pas le marqueur : la correspondance se fait via le siret.
        $this->insertQualimat('TRANSPORTEUR SANS MARQUEUR', true, 'SIRETHIT1');

        $client = $this->createAdminClient();
        $client->request('GET', '/api/qualimat_carriers?search=testqsirethit1', ['headers' => ['Accept' => self::LD]]);
        self::assertResponseIsSuccessful();

        $data = $client->getResponse()->toArray();
        self::assertSame(1, $data['totalItems'], 'La recherche fuzzy doit aussi cibler le siret.');
        self::assertSame('TRANSPORTEUR SANS MARQUEUR', $data['member'][0]['name']);
    }

    public function testCollectionExposesHydraPagination(): void
    {
        $this->insertQualimat('QPAGE UN', true, 'P1');
        $this->insertQualimat('QPAGE DEUX', true, 'P2');
        $this->insertQualimat('QPAGE TROIS', true, 'P3');

        $client = $this->createAdminClient();
        $client->request('GET', '/api/qualimat_carriers?search=qpage&itemsPerPage=2', ['headers' => ['Accept' => self::LD]]);
        self::assertResponseIsSuccessful();

        $data = $client->getResponse()->toArray();
        self::assertArrayHasKey('totalItems', $data, 'La collection doit exposer totalItems.');
        self::assertArrayHasKey('view', $data, 'La collection doit exposer view quand totalItems > itemsPerPage.');
        self::assertIsArray($data['member']);
        self::assertSame(3, $data['totalItems']);
        self::assertCount(2, $data['member'], 'La page doit etre bornee a itemsPerPage=2.');
    }

    public function testForbiddenWithoutPermission(): void
    {
        // Usine : aucun acces transporteurs (matrice § 5.2) -> 403 sur la recherche.
        $client = $this->authenticatedClient('usine', self::PWD);
        $client->request('GET', '/api/qualimat_carriers', ['headers' => ['Accept' => self::LD]]);
        self::assertResponseStatusCodeSame(403);
    }

    /**
     * Insere une ligne qualimat_carrier de test en DBAL brut (l'entite mappee est
     * en lecture seule). SIRET prefixe TESTQ pour la purge ciblee du tearDown.
     */
    private function insertQualimat(string $name, bool $isActive, string $siretSuffix): void
    {
        $this->getEm()->getConnection()->insert('qualimat_carrier', [
            'siret'          => self::SIRET_PREFIX.$siretSuffix,
            'name'           => $name,
            'status'         => 'Valide',
            'validity_date'  => '2027-12-31',
            'is_active'      => $isActive ? 'true' : 'false',
            'last_synced_at' => (new DateTimeImmutable())->format('Y-m-d H:i:s'),
        ]);
    }
}
