<?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\Controller;

use Chill\MainBundle\Controller\WorkflowOnHoldController;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
use Chill\MainBundle\Entity\Workflow\EntityWorkflowStepHold;
use Chill\MainBundle\Workflow\EntityWorkflowMarkingStore;
use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Workflow\DefinitionBuilder;
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 WorkflowOnHoldControllerTest extends TestCase
{
    private function buildRegistry(): Registry
    {
        $definitionBuilder = new DefinitionBuilder();
        $definition = $definitionBuilder
            ->addPlaces(['initial', 'layout', 'sign'])
            ->addTransition(new Transition('to_layout', 'initial', 'layout'))
            ->addTransition(new Transition('to_sign', 'initial', 'sign'))
            ->build();

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

        return $registry;
    }

    public function testPutOnHoldPersistence(): void
    {
        $entityWorkflow = new EntityWorkflow();
        $entityWorkflow->setWorkflowName('dummy_workflow');
        $security = $this->createMock(Security::class);
        $security->method('getUser')->willReturn($user = new User());

        $entityManager = $this->createMock(EntityManagerInterface::class);
        $entityManager->expects($this->once())
            ->method('persist')
            ->with($this->isInstanceOf(EntityWorkflowStepHold::class));

        $entityManager->expects($this->once())
            ->method('flush');

        $urlGenerator = $this->createMock(UrlGeneratorInterface::class);
        $urlGenerator->method('generate')
            ->with('chill_main_workflow_show', ['id' => null])
            ->willReturn('/some/url');

        $controller = new WorkflowOnHoldController($entityManager, $security, $this->buildRegistry(), $urlGenerator);

        $request = new Request();
        $response = $controller->putOnHold($entityWorkflow, $request);

        self::assertEquals(302, $response->getStatusCode());
    }

    public function testRemoveOnHold(): void
    {
        $user = new User();
        $entityWorkflow = new EntityWorkflow();
        $entityWorkflow->setWorkflowName('dummy_workflow');
        $onHold = new EntityWorkflowStepHold($step = $entityWorkflow->getCurrentStep(), $user);

        $security = $this->createMock(Security::class);
        $security->method('getUser')->willReturn($user);

        $entityManager = $this->createMock(EntityManagerInterface::class);
        $entityManager->expects($this->once())
            ->method('remove')
            ->with($onHold);

        $entityManager->expects($this->once())
            ->method('flush');

        $urlGenerator = $this->createMock(UrlGeneratorInterface::class);
        $urlGenerator->method('generate')
            ->with('chill_main_workflow_show', ['id' => null])
            ->willReturn('/some/url');

        $controller = new WorkflowOnHoldController($entityManager, $security, $this->buildRegistry(), $urlGenerator);

        $response = $controller->removeOnHold($step);

        self::assertEquals(302, $response->getStatusCode());
    }
}
