<?php

declare(strict_types=1);

namespace App\Tests\Api\Entity;

use App\Enum\ModelCategory;
use App\Tests\AbstractApiTestCase;

/**
 * @internal
 */
class PieceReferenceAutoTest extends AbstractApiTestCase
{
    public function testReferenceAutoGeneratedAfterAllCfvCreated(): void
    {
        $mt = $this->createModelType('Roulement', 'ROUL-010', ModelCategory::PIECE);
        $mt->setReferenceFormula('{serie}{diametre}{type}');
        $mt->setRequiredFieldsForReference(['serie', 'diametre', 'type']);

        $em = $this->getEntityManager();
        $em->flush();

        $cfSerie    = $this->createCustomField('serie', 'text', typePiece: $mt);
        $cfDiametre = $this->createCustomField('diametre', 'text', typePiece: $mt);
        $cfType     = $this->createCustomField('type', 'text', typePiece: $mt);

        $piece = $this->createPiece('Roulement Auto', null, $mt);

        $this->createCustomFieldValue($cfSerie, '22', piece: $piece);
        $this->createCustomFieldValue($cfDiametre, '07', piece: $piece);
        $this->createCustomFieldValue($cfType, 'K', piece: $piece);

        $client = $this->createViewerClient();
        $client->request('GET', self::iri('pieces', $piece->getId()));

        $this->assertResponseIsSuccessful();
        $this->assertJsonContains(['referenceAuto' => '2207K']);
    }

    public function testReferenceAutoNullWhenNoFormula(): void
    {
        $mt    = $this->createModelType('Galet', 'GAL-010', ModelCategory::PIECE);
        $piece = $this->createPiece('Galet Auto', null, $mt);

        $client   = $this->createViewerClient();
        $response = $client->request('GET', self::iri('pieces', $piece->getId()));

        $this->assertResponseIsSuccessful();
        $data = $response->toArray();
        self::assertArrayNotHasKey('referenceAuto', $data, 'referenceAuto should not be serialized when null');
    }

    public function testReferenceAutoNullWhenRequiredFieldsMissing(): void
    {
        $mt = $this->createModelType('Palier', 'PAL-010', ModelCategory::PIECE);
        $mt->setReferenceFormula('SNU {taille}');
        $mt->setRequiredFieldsForReference(['taille']);

        $em = $this->getEntityManager();
        $em->flush();

        $piece = $this->createPiece('Palier Sans Champ', null, $mt);

        $client   = $this->createViewerClient();
        $response = $client->request('GET', self::iri('pieces', $piece->getId()));

        $this->assertResponseIsSuccessful();
        $data = $response->toArray();
        self::assertArrayNotHasKey('referenceAuto', $data, 'referenceAuto should not be serialized when required fields missing');
    }

    public function testReferenceAutoUpdatedWhenCustomFieldValueChanges(): void
    {
        $mt = $this->createModelType('Joint', 'JOINT-010', ModelCategory::PIECE);
        $mt->setReferenceFormula('U{taille}');

        $em = $this->getEntityManager();
        $em->flush();

        $cfTaille = $this->createCustomField('taille', 'text', typePiece: $mt);
        $piece    = $this->createPiece('Joint Upd', null, $mt);
        $cfv      = $this->createCustomFieldValue($cfTaille, '507', piece: $piece);

        $client = $this->createViewerClient();
        $client->request('GET', self::iri('pieces', $piece->getId()));

        $this->assertResponseIsSuccessful();
        $this->assertJsonContains(['referenceAuto' => 'U507']);

        // Update CFV value via API
        $gClient = $this->createGestionnaireClient();
        $gClient->request('PATCH', self::iri('custom_field_values', $cfv->getId()), [
            'headers' => ['Content-Type' => 'application/merge-patch+json'],
            'json'    => ['value' => '608'],
        ]);

        $this->assertResponseIsSuccessful();

        // Re-read the Piece to check updated referenceAuto
        $viewer = $this->createViewerClient();
        $viewer->request('GET', self::iri('pieces', $piece->getId()));
        $this->assertJsonContains(['referenceAuto' => 'U608']);
    }

    public function testReferenceAutoNullAfterRequiredCfvDeleted(): void
    {
        $mt = $this->createModelType('Joint Del', 'JOINT-011', ModelCategory::PIECE);
        $mt->setReferenceFormula('U{taille}');
        $mt->setRequiredFieldsForReference(['taille']);

        $em = $this->getEntityManager();
        $em->flush();

        $cfTaille = $this->createCustomField('taille', 'text', typePiece: $mt);
        $piece    = $this->createPiece('Joint Del', null, $mt);
        $cfv      = $this->createCustomFieldValue($cfTaille, '507', piece: $piece);

        $client = $this->createViewerClient();
        $client->request('GET', self::iri('pieces', $piece->getId()));
        $this->assertJsonContains(['referenceAuto' => 'U507']);

        // Delete the CFV
        $gClient = $this->createGestionnaireClient();
        $gClient->request('DELETE', self::iri('custom_field_values', $cfv->getId()));
        $this->assertResponseStatusCodeSame(204);

        // Re-read piece — referenceAuto should now be absent (null = not serialized)
        $viewer   = $this->createViewerClient();
        $response = $viewer->request('GET', self::iri('pieces', $piece->getId()));
        $data     = $response->toArray();
        self::assertArrayNotHasKey('referenceAuto', $data, 'referenceAuto should be null after required CFV deleted');
    }

    public function testReferenceAutoIsReadOnlyViaApi(): void
    {
        $piece = $this->createPiece('ReadOnly Test');

        $client = $this->createGestionnaireClient();
        $client->request('PATCH', self::iri('pieces', $piece->getId()), [
            'headers' => ['Content-Type' => 'application/merge-patch+json'],
            'json'    => ['referenceAuto' => 'HACKED'],
        ]);

        $this->assertResponseIsSuccessful();

        // referenceAuto should still be null (no formula) — subscriber overwrites
        $viewer   = $this->createViewerClient();
        $response = $viewer->request('GET', self::iri('pieces', $piece->getId()));
        $data     = $response->toArray();
        self::assertArrayNotHasKey('referenceAuto', $data, 'referenceAuto should not be settable via API');
    }

    public function testReferenceAutoNormalizesLowercaseValues(): void
    {
        $mt = $this->createModelType('Roulement Norm', 'ROUL-011', ModelCategory::PIECE);
        $mt->setReferenceFormula('{serie}{diametre}{type}');

        $em = $this->getEntityManager();
        $em->flush();

        $cfSerie    = $this->createCustomField('serie', 'text', typePiece: $mt);
        $cfDiametre = $this->createCustomField('diametre', 'text', typePiece: $mt);
        $cfType     = $this->createCustomField('type', 'text', typePiece: $mt);

        $piece = $this->createPiece('Roulement Norm', null, $mt);

        $this->createCustomFieldValue($cfSerie, '22', piece: $piece);
        $this->createCustomFieldValue($cfDiametre, '07', piece: $piece);
        $this->createCustomFieldValue($cfType, 'k', piece: $piece);

        $client = $this->createViewerClient();
        $client->request('GET', self::iri('pieces', $piece->getId()));

        $this->assertResponseIsSuccessful();
        $this->assertJsonContains(['referenceAuto' => '2207K']);
    }
}
