<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\MainBundle\Tests\Workflow\EventSubscriber;

use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
use Chill\MainBundle\Workflow\EntityWorkflowMarkingStore;
use Chill\MainBundle\Workflow\EventSubscriber\EntityWorkflowPrepareEmailOnSendExternalEventSubscriber;
use Chill\MainBundle\Workflow\Messenger\PostSendExternalMessage;
use Chill\MainBundle\Workflow\WorkflowTransitionContextDTO;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Workflow\DefinitionBuilder;
use Symfony\Component\Workflow\Metadata\InMemoryMetadataStore;
use Symfony\Component\Workflow\Registry;
use Symfony\Component\Workflow\SupportStrategy\WorkflowSupportStrategyInterface;
use Symfony\Component\Workflow\Transition;
use Symfony\Component\Workflow\Workflow;
use Symfony\Component\Workflow\WorkflowInterface;

/**
 * @internal
 *
 * @coversNothing
 */
class EntityWorkflowPrepareEmailOnSendExternalEventSubscriberTest extends TestCase
{
    use ProphecyTrait;

    private Transition $transitionSendExternal;
    private Transition $transitionRegular;

    public function testToSendExternalGenerateMessage(): void
    {
        $messageBus = $this->prophesize(MessageBusInterface::class);
        $messageBus->dispatch(Argument::type(PostSendExternalMessage::class))
            ->will(fn ($args) => new Envelope($args[0]))
            ->shouldBeCalled();

        $registry = $this->buildRegistry($messageBus->reveal());

        $entityWorkflow = $this->buildEntityWorkflow();
        $dto = new WorkflowTransitionContextDTO($entityWorkflow);

        $workflow = $registry->get($entityWorkflow, $entityWorkflow->getWorkflowName());
        $workflow->apply(
            $entityWorkflow,
            $this->transitionSendExternal->getName(),
            ['context' => $dto, 'byUser' => new User(), 'transition' => $this->transitionSendExternal->getName(),
                'transitionAt' => new \DateTimeImmutable()]
        );

        // at this step, prophecy should check that the dispatch method has been called
    }

    public function testToRegularDoNotGenerateMessage(): void
    {
        $messageBus = $this->prophesize(MessageBusInterface::class);
        $messageBus->dispatch(Argument::type(PostSendExternalMessage::class))
            ->shouldNotBeCalled();

        $registry = $this->buildRegistry($messageBus->reveal());

        $entityWorkflow = $this->buildEntityWorkflow();
        $dto = new WorkflowTransitionContextDTO($entityWorkflow);

        $workflow = $registry->get($entityWorkflow, $entityWorkflow->getWorkflowName());
        $workflow->apply(
            $entityWorkflow,
            $this->transitionRegular->getName(),
            ['context' => $dto, 'byUser' => new User(), 'transition' => $this->transitionRegular->getName(),
                'transitionAt' => new \DateTimeImmutable()]
        );

        // at this step, prophecy should check that the dispatch method has been called
    }

    private function buildEntityWorkflow(): EntityWorkflow
    {
        $entityWorkflow = new EntityWorkflow();
        $entityWorkflow->setWorkflowName('dummy');

        // set an id
        $reflectionClass = new \ReflectionClass($entityWorkflow);
        $idProperty = $reflectionClass->getProperty('id');
        $idProperty->setValue($entityWorkflow, 1);

        return $entityWorkflow;
    }

    private function buildRegistry(MessageBusInterface $messageBus): Registry
    {
        $builder = new DefinitionBuilder(
            ['initial', 'sendExternal', 'regular'],
            [
                $this->transitionSendExternal = new Transition('toSendExternal', 'initial', 'sendExternal'),
                $this->transitionRegular = new Transition('toRegular', 'initial', 'regular'),
            ]
        );

        $builder
            ->setInitialPlaces('initial')
            ->setMetadataStore(new InMemoryMetadataStore(
                placesMetadata: [
                    'sendExternal' => ['isSentExternal' => true],
                ]
            ));

        $entityMarkingStore = new EntityWorkflowMarkingStore();
        $registry = new Registry();

        $eventSubscriber = new EntityWorkflowPrepareEmailOnSendExternalEventSubscriber($registry, $messageBus);
        $eventSubscriber->setLocale('fr');
        $eventDispatcher = new EventDispatcher();
        $eventDispatcher->addSubscriber($eventSubscriber);

        $workflow = new Workflow($builder->build(), $entityMarkingStore, $eventDispatcher, 'dummy');
        $registry->addWorkflow($workflow, new class () implements WorkflowSupportStrategyInterface {
            public function supports(WorkflowInterface $workflow, object $subject): bool
            {
                return true;
            }
        });

        return $registry;
    }
}
