<?php

declare(strict_types=1);

namespace App\Tests\Api\Service;

use App\DTO\SyncConfirmation;
use App\Entity\SkeletonProductRequirement;
use App\Enum\ModelCategory;
use App\Service\Sync\PieceSyncStrategy;
use App\Tests\AbstractApiTestCase;

/**
 * @internal
 */
class PieceSyncStrategyTest extends AbstractApiTestCase
{
    private PieceSyncStrategy $strategy;

    protected function setUp(): void
    {
        parent::setUp();
        $this->strategy = static::getContainer()->get(PieceSyncStrategy::class);
    }

    public function testSupportsPieceCategory(): void
    {
        $mt = $this->createModelType('Piece Cat', 'PC-001', ModelCategory::PIECE);
        $this->assertTrue($this->strategy->supports($mt));
    }

    public function testPreviewDetectsNewProductSlot(): void
    {
        $mt          = $this->createModelType('Piece Cat', 'PC-001', ModelCategory::PIECE);
        $productType = $this->createModelType('Product Type', 'PT-001', ModelCategory::PRODUCT);
        $this->createPiece('P1', 'P1-REF', $mt);

        $result = $this->strategy->preview($mt, [
            'products'     => [['typeProductId' => $productType->getId(), 'position' => 0]],
            'customFields' => [],
        ]);

        $this->assertSame(1, $result->itemCount);
        $this->assertSame(1, $result->additions['productSlots']);
    }

    public function testExecuteAddsProductSlots(): void
    {
        $mt          = $this->createModelType('Piece Cat', 'PC-001', ModelCategory::PIECE);
        $productType = $this->createModelType('Product Type', 'PT-001', ModelCategory::PRODUCT);
        $piece       = $this->createPiece('P1', 'P1-REF', $mt);

        $em  = $this->getEntityManager();
        $req = new SkeletonProductRequirement();
        $req->setModelType($mt);
        $req->setTypeProduct($productType);
        $req->setPosition(0);
        $em->persist($req);
        $em->flush();

        $result = $this->strategy->execute($mt, new SyncConfirmation());

        $this->assertSame(1, $result->itemsUpdated);
        $this->assertSame(1, $result->additions['productSlots']);

        $em->refresh($piece);
        $this->assertSame(2, $piece->getVersion());
        $this->assertCount(1, $piece->getProductSlots());
    }

    public function testExecuteDeletesWithConfirmation(): void
    {
        $mt          = $this->createModelType('Piece Cat', 'PC-001', ModelCategory::PIECE);
        $productType = $this->createModelType('Product Type', 'PT-001', ModelCategory::PRODUCT);
        $piece       = $this->createPiece('P1', 'P1-REF', $mt);
        $this->createPieceProductSlot($piece, $productType, null, null, 0);

        $result = $this->strategy->execute($mt, new SyncConfirmation(confirmDeletions: true));
        $this->assertSame(1, $result->deletions['productSlots']);
    }

    public function testExecuteIsIdempotent(): void
    {
        $mt          = $this->createModelType('Piece Cat', 'PC-001', ModelCategory::PIECE);
        $productType = $this->createModelType('Product Type', 'PT-001', ModelCategory::PRODUCT);
        $piece       = $this->createPiece('P1', 'P1-REF', $mt);

        $em  = $this->getEntityManager();
        $req = new SkeletonProductRequirement();
        $req->setModelType($mt);
        $req->setTypeProduct($productType);
        $req->setPosition(0);
        $em->persist($req);
        $em->flush();

        $result1 = $this->strategy->execute($mt, new SyncConfirmation());
        $this->assertSame(1, $result1->additions['productSlots']);

        $em->refresh($piece);
        $result2 = $this->strategy->execute($mt, new SyncConfirmation());
        $this->assertSame(0, $result2->itemsUpdated);
    }
}
