<?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\Workflow\EntityWorkflow;
use Chill\MainBundle\Workflow\EntityWorkflowManager;
use Chill\MainBundle\Workflow\EntityWorkflowMarkingStore;
use Chill\MainBundle\Workflow\EventSubscriber\BlockSignatureOnRelatedEntityWithoutAnyStoredObjectGuard;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Symfony\Component\EventDispatcher\EventDispatcher;
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 BlockSignatureOnRelatedEntityWithoutAnyStoredObjectGuardTest extends TestCase
{
    use ProphecyTrait;

    public function testAllowedForSignatureOnRelatedEntityWithStoredObject(): void
    {
        $entityWorkflow = new EntityWorkflow();
        $entityWorkflow->setWorkflowName('dummy')->setRelatedEntityClass('with_stored_object');

        $registry = $this->buildRegistry();
        $workflow = $registry->get($entityWorkflow, $entityWorkflow->getWorkflowName());

        $list = $workflow->buildTransitionBlockerList($entityWorkflow, 'to_signature');

        self::assertCount(0, $list);
    }

    public function testBlockForSignatureOnRelatedEntityWithoutStoredObject(): void
    {
        $entityWorkflow = new EntityWorkflow();
        $entityWorkflow->setWorkflowName('dummy')->setRelatedEntityClass('no_stored_object');

        $registry = $this->buildRegistry();
        $workflow = $registry->get($entityWorkflow, $entityWorkflow->getWorkflowName());

        $list = $workflow->buildTransitionBlockerList($entityWorkflow, 'to_signature');

        self::assertCount(1, $list);
        self::assertTrue($list->has('e8e28caa-a106-11ef-97e8-f3919e8b5c8a'));
    }

    public function testAllowedForNoSignatureOnRelatedEntityWithoutStoredObject(): void
    {
        $entityWorkflow = new EntityWorkflow();
        $entityWorkflow->setWorkflowName('dummy')->setRelatedEntityClass('no_stored_object');

        $registry = $this->buildRegistry();
        $workflow = $registry->get($entityWorkflow, $entityWorkflow->getWorkflowName());

        $list = $workflow->buildTransitionBlockerList($entityWorkflow, 'to_no_signature');

        self::assertTrue($list->isEmpty());
    }

    public function testAllowedForNoSignatureOnRelatedEntityWithStoredObject(): void
    {
        $entityWorkflow = new EntityWorkflow();
        $entityWorkflow->setWorkflowName('dummy')->setRelatedEntityClass('no_stored_object');

        $registry = $this->buildRegistry();
        $workflow = $registry->get($entityWorkflow, $entityWorkflow->getWorkflowName());

        $list = $workflow->buildTransitionBlockerList($entityWorkflow, 'to_no_signature');

        self::assertTrue($list->isEmpty());
    }

    private function buildRegistry(): Registry
    {
        $definitionBuilder = new DefinitionBuilder();
        $definitionBuilder
            ->addPlaces(['initial', 'signature', 'no_signature'])
            ->addTransition(
                new Transition('to_signature', 'initial', 'signature')
            )
            ->addTransition(
                new Transition('to_no_signature', 'initial', 'no_signature')
            )
            ->setMetadataStore(
                new InMemoryMetadataStore(
                    placesMetadata: ['signature' => ['isSignature' => ['person']]]
                )
            );

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

        $entityWorkflowManager = $this->prophesize(EntityWorkflowManager::class);
        $entityWorkflowManager->canAssociateStoredObject(Argument::type(EntityWorkflow::class))->will(
            function ($args): bool {
                /** @var EntityWorkflow $entityWorkflow */
                $entityWorkflow = $args[0];

                return 'with_stored_object' === $entityWorkflow->getRelatedEntityClass();
            }
        );
        $eventSubscriber = new BlockSignatureOnRelatedEntityWithoutAnyStoredObjectGuard(
            $entityWorkflowManager->reveal()
        );

        $eventDispatcher->addSubscriber($eventSubscriber);

        return $registry;
    }
}
