<?php

declare(strict_types=1);

namespace CpCreation\VitiCore\Tests\Commerce\Catalog\Enrollment;

use CpCreation\VitiCore\Bridge\Doctrine\EventSubscriber\CatalogEnrollmentSubscriber;
use CpCreation\VitiCore\Commerce\Catalog\Enrollment\Model\CatalogEnrollmentRequest;
use CpCreation\VitiCore\Commerce\Catalog\Model\CatalogConfiguration;
use CpCreation\VitiCore\Product\Model\ProductCategory;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\UnitOfWork;
use PHPUnit\Framework\TestCase;

final class CatalogEnrollmentSubscriberTest extends TestCase
{
    public function testItAddsOnlyAnUnpreparedOutboxSignalDuringCategoryInsertion(): void
    {
        $category = new ProductCategory();
        $category->setCommerceExportEnabled(true);
        $unitOfWork = $this->createMock(UnitOfWork::class);
        $unitOfWork->method('getScheduledEntityInsertions')->willReturn([$category]);
        $unitOfWork->method('getScheduledEntityUpdates')->willReturn([]);
        $metadata = new ClassMetadata(CatalogEnrollmentRequest::class);
        $unitOfWork->expects(self::once())
            ->method('computeChangeSet')
            ->with($metadata, self::callback(static fn(object $request): bool => $request instanceof CatalogEnrollmentRequest
                && !$request->isPrepared()));
        $entityManager = $this->createMock(EntityManagerInterface::class);
        $entityManager->method('getUnitOfWork')->willReturn($unitOfWork);
        $entityManager->method('getClassMetadata')->with(CatalogEnrollmentRequest::class)->willReturn($metadata);
        $entityManager->expects(self::once())
            ->method('persist')
            ->with(self::isInstanceOf(CatalogEnrollmentRequest::class));
        $entityManager->expects(self::never())->method('flush');

        new CatalogEnrollmentSubscriber()->onFlush(new OnFlushEventArgs($entityManager));
    }

    public function testItDoesNotSignalADisabledCategoryInsertion(): void
    {
        $unitOfWork = $this->createStub(UnitOfWork::class);
        $unitOfWork->method('getScheduledEntityInsertions')->willReturn([new ProductCategory()]);
        $unitOfWork->method('getScheduledEntityUpdates')->willReturn([]);
        $entityManager = $this->createMock(EntityManagerInterface::class);
        $entityManager->method('getUnitOfWork')->willReturn($unitOfWork);
        $entityManager->expects(self::never())->method('persist');

        new CatalogEnrollmentSubscriber()->onFlush(new OnFlushEventArgs($entityManager));
    }

    public function testItSignalsTheFalseToTrueTransition(): void
    {
        $category = new ProductCategory();
        $category->setCommerceExportEnabled(true);
        $unitOfWork = $this->createMock(UnitOfWork::class);
        $unitOfWork->method('getScheduledEntityInsertions')->willReturn([]);
        $unitOfWork->method('getScheduledEntityUpdates')->willReturn([$category]);
        $unitOfWork->method('getEntityChangeSet')->with($category)->willReturn([
            'commerceExportEnabled' => [false, true],
        ]);
        $metadata = new ClassMetadata(CatalogEnrollmentRequest::class);
        $unitOfWork->expects(self::once())->method('computeChangeSet')->with($metadata, self::isInstanceOf(CatalogEnrollmentRequest::class));
        $entityManager = $this->createMock(EntityManagerInterface::class);
        $entityManager->method('getUnitOfWork')->willReturn($unitOfWork);
        $entityManager->method('getClassMetadata')->willReturn($metadata);
        $entityManager->expects(self::once())->method('persist')->with(self::isInstanceOf(CatalogEnrollmentRequest::class));

        new CatalogEnrollmentSubscriber()->onFlush(new OnFlushEventArgs($entityManager));
    }

    public function testItSignalsTheGlobalCommerceActivationWithoutAnExportedCategory(): void
    {
        $configuration = new CatalogConfiguration();
        $configuration->setEnabled(true);
        $unitOfWork = $this->createMock(UnitOfWork::class);
        $unitOfWork->method('getScheduledEntityInsertions')->willReturn([]);
        $unitOfWork->method('getScheduledEntityUpdates')->willReturn([$configuration]);
        $unitOfWork->method('getEntityChangeSet')->with($configuration)->willReturn([
            'enabled' => [false, true],
        ]);
        $metadata = new ClassMetadata(CatalogEnrollmentRequest::class);
        $unitOfWork->expects(self::once())->method('computeChangeSet')->with($metadata, self::isInstanceOf(CatalogEnrollmentRequest::class));
        $entityManager = $this->createMock(EntityManagerInterface::class);
        $entityManager->method('getUnitOfWork')->willReturn($unitOfWork);
        $entityManager->method('getClassMetadata')->willReturn($metadata);
        $entityManager->expects(self::once())->method('persist')->with(self::isInstanceOf(CatalogEnrollmentRequest::class));

        new CatalogEnrollmentSubscriber()->onFlush(new OnFlushEventArgs($entityManager));
    }
}
