<?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\UserGroup;
use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
use Chill\MainBundle\Workflow\EntityWorkflowHandlerInterface;
use Chill\MainBundle\Workflow\EntityWorkflowManager;
use Chill\MainBundle\Workflow\EntityWorkflowMarkingStore;
use Chill\MainBundle\Workflow\EventSubscriber\NotificationToUserGroupsOnTransition;
use Chill\MainBundle\Workflow\Helper\MetadataExtractor;
use Chill\MainBundle\Workflow\WorkflowTransitionContextDTO;
use Doctrine\ORM\EntityManagerInterface;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\BodyRendererInterface;
use Symfony\Component\Mime\RawMessage;
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;
use Twig\Environment;

/**
 * @internal
 *
 * @coversNothing
 */
class NotificationToUserGroupsOnTransitionTest extends KernelTestCase
{
    use ProphecyTrait;
    private Environment $twig;
    private BodyRendererInterface $bodyRenderer;
    private EntityManagerInterface $em;

    protected function setUp(): void
    {
        self::bootKernel();
        $this->twig = self::getContainer()->get('twig');
        $this->bodyRenderer = self::getContainer()->get(BodyRendererInterface::class);
        $this->em = self::getContainer()->get('doctrine.orm.entity_manager');
    }

    public function testOnCompletedSendNotificationToUserGroupWithEmailAddress(): void
    {
        $entityWorkflow = new EntityWorkflow();
        $this->em->persist($entityWorkflow);

        $entityWorkflow->setWorkflowName('dummy');
        $dto = new WorkflowTransitionContextDTO($entityWorkflow);
        $dto->futureDestUsers = [$ug = new UserGroup()];
        $ug->setEmail('test@email.com')->setLabel(['fr' => 'test group']);

        $mailer = $this->prophesize(MailerInterface::class);
        $sendMethod = $mailer->send(Argument::that(function (RawMessage $message): bool {
            if (!$message instanceof TemplatedEmail) {
                return false;
            }

            $this->bodyRenderer->render($message);

            return 'test@email.com' === $message->getTo()[0]->getAddress();
        }));
        $sendMethod->shouldBeCalledOnce();

        $metadataExtractor = $this->prophesize(MetadataExtractor::class);
        $metadataExtractor->buildArrayPresentationForWorkflow(Argument::type(Workflow::class))->willReturn(['name' => 'dummy', 'text' => 'Dummy Workflow']);
        $metadataExtractor->buildArrayPresentationForPlace($entityWorkflow)->willReturn(['name' => 'to_one', 'text' => 'Dummy Place']);

        $entityWorkflowHandler = $this->prophesize(EntityWorkflowHandlerInterface::class);
        $entityWorkflowHandler->getEntityTitle($entityWorkflow)->willReturn('My title');
        $entityWorkflowManager = $this->prophesize(EntityWorkflowManager::class);
        $entityWorkflowManager->getHandler($entityWorkflow)->willReturn($entityWorkflowHandler->reveal());

        $registry = $this->buildRegistryWithEventSubscriber($mailer->reveal(), $metadataExtractor->reveal(), $entityWorkflowManager->reveal());
        $workflow = $registry->get($entityWorkflow, 'dummy');

        $workflow->apply($entityWorkflow, 'to_one', ['context' => $dto, 'transition' => 'to_one', 'transitionAt' => new \DateTimeImmutable(), 'byUser' => new User()]);
    }

    public function testOnCompletedSendNotificationToUserGroupWithoutAnyEmailAddress(): void
    {
        $entityWorkflow = new EntityWorkflow();
        $reflection = new \ReflectionClass($entityWorkflow);
        $idProperty = $reflection->getProperty('id');
        $idProperty->setValue($entityWorkflow, 1);

        $entityWorkflow->setWorkflowName('dummy');
        $dto = new WorkflowTransitionContextDTO($entityWorkflow);
        $dto->futureDestUsers = [$ug = new UserGroup()];

        $mailer = $this->prophesize(MailerInterface::class);
        $mailer->send(Argument::any())->shouldNotBeCalled();

        $metadataExtractor = $this->prophesize(MetadataExtractor::class);
        $metadataExtractor->buildArrayPresentationForWorkflow(Argument::type(Workflow::class))->willReturn(['name' => 'dummy', 'text' => 'Dummy Workflow']);
        $metadataExtractor->buildArrayPresentationForPlace($entityWorkflow)->willReturn(['name' => 'to_one', 'text' => 'Dummy Place']);

        $entityWorkflowHandler = $this->prophesize(EntityWorkflowHandlerInterface::class);
        $entityWorkflowHandler->getEntityTitle($entityWorkflow)->willReturn('My title');
        $entityWorkflowManager = $this->prophesize(EntityWorkflowManager::class);
        $entityWorkflowManager->getHandler($entityWorkflow)->willReturn($entityWorkflowHandler->reveal());

        $registry = $this->buildRegistryWithEventSubscriber($mailer->reveal(), $metadataExtractor->reveal(), $entityWorkflowManager->reveal());
        $workflow = $registry->get($entityWorkflow, 'dummy');

        $workflow->apply($entityWorkflow, 'to_one', ['context' => $dto, 'transition' => 'to_one', 'transitionAt' => new \DateTimeImmutable(), 'byUser' => new User()]);
    }

    private function buildRegistryWithEventSubscriber(MailerInterface $mailer, MetadataExtractor $metadataExtractor, EntityWorkflowManager $entityWorkflowManager): Registry
    {
        $builder = new DefinitionBuilder();
        $builder
            ->setInitialPlaces('initial')
            ->addPlaces(['initial', 'to_one'])
            ->addTransition(new Transition('to_one', 'initial', 'to_one'));

        $metadata = new InMemoryMetadataStore(
            ['label' => ['fr' => 'dummy workflow']],
        );
        $builder->setMetadataStore($metadata);

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

        $notificationEventSubscriber = new NotificationToUserGroupsOnTransition($this->twig, $metadataExtractor, $registry, $mailer, $this->em, $entityWorkflowManager);
        $eventDispatcher->addSubscriber($notificationEventSubscriber);

        return $registry;
    }
}
