<?php

declare(strict_types=1);

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

use CpCreation\VitiCore\Commerce\Catalog\Enrollment\CatalogEnrollmentContext;
use CpCreation\VitiCore\Commerce\Catalog\Enrollment\CatalogEnrollmentPayload;
use CpCreation\VitiCore\Commerce\Catalog\Enrollment\CatalogEnrollmentPayloadProvider;
use CpCreation\VitiCore\Commerce\Catalog\Enrollment\Message\DeliverCatalogEnrollmentMessage;
use CpCreation\VitiCore\Commerce\Catalog\Enrollment\Message\DispatchCatalogEnrollmentsMessage;
use CpCreation\VitiCore\Commerce\Catalog\Enrollment\Message\DispatchCatalogEnrollmentsMessageHandler;
use CpCreation\VitiCore\Commerce\Catalog\Enrollment\Model\CatalogEnrollmentRequest;
use CpCreation\VitiCore\Commerce\Catalog\Enrollment\Repository\CatalogEnrollmentRequestStore;
use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\MessageBusInterface;

final class DispatchCatalogEnrollmentsMessageHandlerTest extends TestCase
{
    private const string INSTANCE_ID = '7ad9e145-910f-4de4-9cec-5f832494adef';
    private const string FINGERPRINT = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';

    public function testItPreparesClaimsAndDispatchesTheTransactionalActivationSignal(): void
    {
        $request = new CatalogEnrollmentRequest();
        $context = $this->context();
        $payloadProvider = $this->createStub(CatalogEnrollmentPayloadProvider::class);
        $payloadProvider->method('currentContext')->willReturn($context);
        $store = $this->createMock(CatalogEnrollmentRequestStore::class);
        $store->expects(self::once())->method('findUnprepared')->willReturn([$request]);
        $store->expects(self::once())->method('existsForFingerprint')->with(self::FINGERPRINT)->willReturn(true);
        $store->expects(self::once())->method('findReadyForDelivery')->willReturn([$request]);
        $entityManager = $this->createMock(EntityManagerInterface::class);
        $entityManager->expects(self::exactly(2))->method('flush');
        $bus = $this->createMock(MessageBusInterface::class);
        $bus->expects(self::once())
            ->method('dispatch')
            ->with(self::callback(static fn(object $message): bool => $message instanceof DeliverCatalogEnrollmentMessage
                && $message->requestId === $request->getRequestId()->toString()))
            ->willReturnCallback(static fn(object $message): Envelope => new Envelope($message));

        (new DispatchCatalogEnrollmentsMessageHandler(
            $payloadProvider,
            $store,
            $entityManager,
            $bus,
        ))(new DispatchCatalogEnrollmentsMessage());

        self::assertTrue($request->isPrepared());
        self::assertSame(self::FINGERPRINT, $request->getConfigurationFingerprint());
    }

    public function testItCreatesCatchUpRequestForAnEnabledGlobalConfigurationEvenWithoutCategory(): void
    {
        $payloadProvider = $this->createStub(CatalogEnrollmentPayloadProvider::class);
        $payloadProvider->method('currentContext')->willReturn($this->context());
        $store = $this->createMock(CatalogEnrollmentRequestStore::class);
        $store->method('findUnprepared')->willReturn([]);
        $store->expects(self::once())->method('existsForFingerprint')->willReturn(false);
        $store->method('findReadyForDelivery')->willReturn([]);
        $entityManager = $this->createMock(EntityManagerInterface::class);
        $entityManager->expects(self::once())
            ->method('persist')
            ->with(self::callback(static fn(object $request): bool => $request instanceof CatalogEnrollmentRequest
                && self::FINGERPRINT === $request->getConfigurationFingerprint()));
        $entityManager->expects(self::once())->method('flush');
        $bus = $this->createStub(MessageBusInterface::class);

        (new DispatchCatalogEnrollmentsMessageHandler(
            $payloadProvider,
            $store,
            $entityManager,
            $bus,
        ))(new DispatchCatalogEnrollmentsMessage());
    }

    private function context(): CatalogEnrollmentContext
    {
        $payload = new CatalogEnrollmentPayload(
            '1.0',
            self::INSTANCE_ID,
            'Champagne Exemple',
            'Champagne Exemple SAS',
            'https://champagne.example',
            'viticore',
            '0123456789abcdef0123456789abcdef',
        );

        return new CatalogEnrollmentContext(self::INSTANCE_ID, self::FINGERPRINT, $payload);
    }
}
