<?php

declare(strict_types=1);

namespace App\Tests\Mcp\Tool\Machine;

use App\Tests\AbstractApiTestCase;

/**
 * @internal
 */
class MachineStructureToolTest extends AbstractApiTestCase
{
    public function testGetMachineStructure(): void
    {
        $site      = $this->createSite(name: 'Site Structure');
        $machine   = $this->createMachine(name: 'Machine Structure', site: $site, reference: 'REF-STRUCT');
        $composant = $this->createComposant(name: 'Composant Alpha');
        $piece     = $this->createPiece(name: 'Piece Alpha', reference: 'REF-P1');
        $product   = $this->createProduct(name: 'Product Alpha', reference: 'REF-PR1');

        $componentLink = $this->createMachineComponentLink($machine, $composant);
        $this->createMachinePieceLink($machine, $piece, $componentLink, quantity: 3);
        $this->createMachineProductLink($machine, $product);

        $session = $this->createMcpClient('ROLE_VIEWER');

        $data = $this->callMcpTool($session, 'get_machine_structure', [
            'machineId' => $machine->getId(),
        ]);

        $this->assertArrayHasKey('_parsed', $data);
        $parsed = $data['_parsed'];

        // Machine info
        $this->assertSame('Machine Structure', $parsed['machine']['name']);
        $this->assertSame('REF-STRUCT', $parsed['machine']['reference']);
        $this->assertSame($site->getId(), $parsed['machine']['siteId']);

        // Component links
        $this->assertCount(1, $parsed['componentLinks']);
        $this->assertSame($composant->getId(), $parsed['componentLinks'][0]['composantId']);
        $this->assertSame('Composant Alpha', $parsed['componentLinks'][0]['composant']['name']);

        // Piece links
        $this->assertCount(1, $parsed['pieceLinks']);
        $this->assertSame($piece->getId(), $parsed['pieceLinks'][0]['pieceId']);
        $this->assertSame('Piece Alpha', $parsed['pieceLinks'][0]['piece']['name']);
        $this->assertSame(3, $parsed['pieceLinks'][0]['quantity']);

        // Product links
        $this->assertCount(1, $parsed['productLinks']);
        $this->assertSame($product->getId(), $parsed['productLinks'][0]['productId']);
        $this->assertSame('Product Alpha', $parsed['productLinks'][0]['product']['name']);
    }

    public function testGetMachineStructureNotFound(): void
    {
        $session = $this->createMcpClient('ROLE_VIEWER');

        $data = $this->callMcpTool($session, 'get_machine_structure', [
            'machineId' => 'nonexistent-id',
        ]);

        $this->assertArrayHasKey('error', $data);
    }

    public function testGetMachineStructureWithOverrides(): void
    {
        $site      = $this->createSite(name: 'Site Overrides');
        $machine   = $this->createMachine(name: 'Machine Overrides', site: $site);
        $composant = $this->createComposant(name: 'Composant Override');

        $componentLink = $this->createMachineComponentLink($machine, $composant);
        $componentLink->setNameOverride('Custom Name');
        $componentLink->setReferenceOverride('CUSTOM-REF');
        $this->getEntityManager()->flush();

        $session = $this->createMcpClient('ROLE_VIEWER');

        $data = $this->callMcpTool($session, 'get_machine_structure', [
            'machineId' => $machine->getId(),
        ]);

        $this->assertArrayHasKey('_parsed', $data);
        $overrides = $data['_parsed']['componentLinks'][0]['overrides'];
        $this->assertSame('Custom Name', $overrides['name']);
        $this->assertSame('CUSTOM-REF', $overrides['reference']);
    }

    public function testCloneMachine(): void
    {
        $site       = $this->createSite(name: 'Site Source');
        $targetSite = $this->createSite(name: 'Site Target');
        $machine    = $this->createMachine(name: 'Machine Source', site: $site, reference: 'REF-SRC');
        $composant  = $this->createComposant(name: 'Composant Clone');
        $piece      = $this->createPiece(name: 'Piece Clone');
        $product    = $this->createProduct(name: 'Product Clone');

        $componentLink = $this->createMachineComponentLink($machine, $composant);
        $this->createMachinePieceLink($machine, $piece, $componentLink, quantity: 2);
        $this->createMachineProductLink($machine, $product);

        $session = $this->createMcpClient('ROLE_GESTIONNAIRE');

        $data = $this->callMcpTool($session, 'clone_machine', [
            'machineId' => $machine->getId(),
            'name'      => 'Machine Cloned',
            'siteId'    => $targetSite->getId(),
            'reference' => 'REF-CLN',
        ]);

        $this->assertArrayHasKey('_parsed', $data);
        $parsed = $data['_parsed'];

        $this->assertSame('Machine Cloned', $parsed['name']);
        $this->assertSame('REF-CLN', $parsed['reference']);
        $this->assertSame($targetSite->getId(), $parsed['siteId']);
        $this->assertSame($machine->getId(), $parsed['clonedFrom']);
        $this->assertNotSame($machine->getId(), $parsed['id']);

        // Verify the cloned machine has links by fetching its structure
        $structureData = $this->callMcpTool($session, 'get_machine_structure', [
            'machineId' => $parsed['id'],
        ]);

        $this->assertArrayHasKey('_parsed', $structureData);
        $structure = $structureData['_parsed'];

        $this->assertCount(1, $structure['componentLinks']);
        $this->assertSame($composant->getId(), $structure['componentLinks'][0]['composantId']);
        $this->assertCount(1, $structure['pieceLinks']);
        $this->assertCount(1, $structure['productLinks']);
    }

    public function testCloneMachineRequiresGestionnaire(): void
    {
        $site    = $this->createSite(name: 'Site Forbidden');
        $machine = $this->createMachine(name: 'Machine Forbidden', site: $site);
        $session = $this->createMcpClient('ROLE_VIEWER');

        $data = $this->callMcpTool($session, 'clone_machine', [
            'machineId' => $machine->getId(),
            'name'      => 'Should Fail',
            'siteId'    => $site->getId(),
        ]);

        $this->assertArrayHasKey('error', $data, 'Should fail with VIEWER role');
    }

    public function testCloneMachineNotFound(): void
    {
        $site    = $this->createSite(name: 'Site Clone NF');
        $session = $this->createMcpClient('ROLE_GESTIONNAIRE');

        $data = $this->callMcpTool($session, 'clone_machine', [
            'machineId' => 'nonexistent-id',
            'name'      => 'Should Fail',
            'siteId'    => $site->getId(),
        ]);

        $this->assertArrayHasKey('error', $data);
    }
}
