<?php

declare(strict_types=1);

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

use CpCreation\VitiCore\Bridge\Doctrine\EventSubscriber\CatalogChangeSubscriber;
use CpCreation\VitiCore\Commerce\Catalog\CatalogIdentity;
use CpCreation\VitiCore\Commerce\Catalog\Configuration\CatalogIntegrationConfiguration;
use CpCreation\VitiCore\Commerce\Catalog\Model\CatalogChange;
use CpCreation\VitiCore\Commerce\Catalog\Model\CatalogChangeType;
use CpCreation\VitiCore\Commerce\Catalog\Model\CatalogResourceType;
use CpCreation\VitiCore\Commerce\Catalog\Outbox\CatalogChangeClassifier;
use CpCreation\VitiCore\Product\Model\CommerceProductType;
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\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;

final class ProductCategoryComplianceChangeTest extends TestCase
{
    /**
     * @param array{0: mixed, 1: mixed} $change
     */
    #[DataProvider('commerceComplianceChanges')]
    public function testChangingCategoryComplianceRequiresCatalogReconciliation(string $field, array $change): void
    {
        $category = new ProductCategory();
        $unitOfWork = $this->createMock(UnitOfWork::class);
        $unitOfWork->method('getScheduledEntityInsertions')->willReturn([]);
        $unitOfWork->method('getScheduledEntityUpdates')->willReturn([$category]);
        $unitOfWork->method('getScheduledEntityDeletions')->willReturn([]);
        $unitOfWork->method('getScheduledCollectionUpdates')->willReturn([]);
        $unitOfWork->method('getScheduledCollectionDeletions')->willReturn([]);
        $unitOfWork->method('getEntityChangeSet')->with($category)->willReturn([$field => $change]);

        $persistedChanges = [];
        $entityManager = $this->createMock(EntityManagerInterface::class);
        $entityManager->method('getUnitOfWork')->willReturn($unitOfWork);
        $entityManager->method('getClassMetadata')->with(CatalogChange::class)->willReturn(new ClassMetadata(CatalogChange::class));
        $entityManager->method('persist')->willReturnCallback(
            static function (object $entity) use (&$persistedChanges): void {
                if ($entity instanceof CatalogChange) {
                    $persistedChanges[] = $entity;
                }
            },
        );

        $configuration = new CatalogIntegrationConfiguration(
            enabled: true,
            instanceId: '7ad9e145-910f-4de4-9cec-5f832494adef',
            apiTokenHash: '',
            currency: 'EUR',
        );
        $subscriber = new CatalogChangeSubscriber(
            $configuration,
            new CatalogChangeClassifier(new CatalogIdentity($configuration)),
        );

        $subscriber->onFlush(new OnFlushEventArgs($entityManager));

        self::assertCount(1, $persistedChanges);
        self::assertSame(CatalogChangeType::RECONCILIATION_REQUIRED, $persistedChanges[0]->getType());
        self::assertSame(CatalogResourceType::CATALOG, $persistedChanges[0]->getResourceType());
        self::assertNull($persistedChanges[0]->getResourceId());
    }

    /**
     * @return iterable<string, array{string, array{0: mixed, 1: mixed}}>
     */
    public static function commerceComplianceChanges(): iterable
    {
        yield 'activation de l’export' => ['commerceExportEnabled', [false, true]];
        yield 'classification réelle du contenu' => ['commerceProductType', [CommerceProductType::UNKNOWN, CommerceProductType::ALCOHOL]];
        yield 'âge minimum d’achat' => ['minimumPurchaseAge', [null, 18]];
    }
}
