<?php

declare(strict_types=1);

namespace App\Tests\Api\Controller;

use App\Tests\AbstractApiTestCase;

/**
 * @internal
 */
class EntityVersionTest extends AbstractApiTestCase
{
    // ── Versions list ───────────────────────────────────────────────

    public function testMachineVersionsAfterCreateAndUpdate(): void
    {
        $machine = $this->createMachine('Machine V');

        $gClient = $this->createGestionnaireClient();
        $gClient->request('PATCH', self::iri('machines', $machine->getId()), [
            'headers' => ['Content-Type' => 'application/merge-patch+json'],
            'json'    => ['name' => 'Machine V Updated'],
        ]);
        $this->assertResponseIsSuccessful();

        $vClient = $this->createViewerClient();
        $vClient->request('GET', sprintf('/api/machines/%s/versions', $machine->getId()));
        $this->assertResponseIsSuccessful();

        $data = $vClient->getResponse()->toArray();
        $this->assertArrayHasKey('items', $data);
        $this->assertArrayHasKey('total', $data);
        $this->assertGreaterThanOrEqual(1, $data['total']);

        $firstItem = $data['items'][0];
        $this->assertArrayHasKey('version', $firstItem);
        $this->assertArrayHasKey('action', $firstItem);
        $this->assertArrayHasKey('createdAt', $firstItem);
    }

    public function testComposantVersionsList(): void
    {
        $composant = $this->createComposant('Composant V');

        $client = $this->createViewerClient();
        $client->request('GET', sprintf('/api/composants/%s/versions', $composant->getId()));
        $this->assertResponseIsSuccessful();

        $data = $client->getResponse()->toArray();
        $this->assertArrayHasKey('items', $data);
    }

    public function testPieceVersionsList(): void
    {
        $piece = $this->createPiece('Piece V');

        $client = $this->createViewerClient();
        $client->request('GET', sprintf('/api/pieces/%s/versions', $piece->getId()));
        $this->assertResponseIsSuccessful();
    }

    public function testProductVersionsList(): void
    {
        $product = $this->createProduct('Product V');

        $client = $this->createViewerClient();
        $client->request('GET', sprintf('/api/products/%s/versions', $product->getId()));
        $this->assertResponseIsSuccessful();
    }

    public function testVersionsNotFound(): void
    {
        $client = $this->createViewerClient();
        $client->request('GET', '/api/machines/nonexistent-id/versions');
        $this->assertResponseStatusCodeSame(404);
    }

    public function testVersionsUnauthenticated(): void
    {
        $machine = $this->createMachine('Machine V');

        $client = $this->createUnauthenticatedClient();
        $client->request('GET', sprintf('/api/machines/%s/versions', $machine->getId()));
        $this->assertResponseStatusCodeSame(401);
    }

    // ── Preview ─────────────────────────────────────────────────────

    public function testPreviewRequiresGestionnaire(): void
    {
        $machine = $this->createMachine('Machine P');

        $client = $this->createViewerClient();
        $client->request('GET', sprintf('/api/machines/%s/versions/1/preview', $machine->getId()));
        $this->assertResponseStatusCodeSame(403);
    }

    public function testPreviewReturnsRestoreInfo(): void
    {
        $composant = $this->createComposant('Composant P');

        // Update to create version 2
        $gClient = $this->createGestionnaireClient();
        $gClient->request('PATCH', self::iri('composants', $composant->getId()), [
            'headers' => ['Content-Type' => 'application/merge-patch+json'],
            'json'    => ['name' => 'Composant P Updated'],
        ]);
        $this->assertResponseIsSuccessful();

        // Preview restore to version 1
        $gClient2 = $this->createGestionnaireClient();
        $gClient2->request('GET', sprintf('/api/composants/%s/versions/1/preview', $composant->getId()));
        $this->assertResponseIsSuccessful();

        $data = $gClient2->getResponse()->toArray();
        $this->assertArrayHasKey('version', $data);
        $this->assertArrayHasKey('restoreMode', $data);
        $this->assertArrayHasKey('diff', $data);
        $this->assertArrayHasKey('warnings', $data);
        $this->assertEquals(1, $data['version']);
        $this->assertEquals('full', $data['restoreMode']);
    }

    // ── Restore ─────────────────────────────────────────────────────

    public function testRestoreRequiresGestionnaire(): void
    {
        $machine = $this->createMachine('Machine R');

        $client = $this->createViewerClient();
        $client->request('POST', sprintf('/api/machines/%s/versions/1/restore', $machine->getId()));
        $this->assertResponseStatusCodeSame(403);
    }

    public function testRestoreCreatesNewVersion(): void
    {
        $composant = $this->createComposant('Original Name');

        // Update
        $gClient = $this->createGestionnaireClient();
        $gClient->request('PATCH', self::iri('composants', $composant->getId()), [
            'headers' => ['Content-Type' => 'application/merge-patch+json'],
            'json'    => ['name' => 'Updated Name'],
        ]);
        $this->assertResponseIsSuccessful();

        // Restore to version 1
        $gClient2 = $this->createGestionnaireClient();
        $gClient2->request('POST', sprintf('/api/composants/%s/versions/1/restore', $composant->getId()));
        $this->assertResponseIsSuccessful();

        $data = $gClient2->getResponse()->toArray();
        $this->assertTrue($data['success']);
        $this->assertEquals(1, $data['restoredFromVersion']);
        $this->assertGreaterThan(2, $data['newVersion']);

        // Verify the name was restored
        $vClient = $this->createViewerClient();
        $vClient->request('GET', self::iri('composants', $composant->getId()));
        $this->assertResponseIsSuccessful();
        $entityData = $vClient->getResponse()->toArray();
        $this->assertEquals('Original Name', $entityData['name']);
    }

    public function testRestoreVersionNotFound(): void
    {
        $composant = $this->createComposant('Composant NF');

        $client = $this->createGestionnaireClient();
        $client->request('POST', sprintf('/api/composants/%s/versions/999/restore', $composant->getId()));
        $this->assertResponseStatusCodeSame(404);
    }
}
