<?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\DocGeneratorBundle\tests\Service\Messenger;

use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate;
use Chill\DocGeneratorBundle\Service\Messenger\OnAfterMessageHandledClearStoredObjectCache;
use Chill\DocGeneratorBundle\Service\Messenger\RequestGenerationMessage;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Service\StoredObjectManagerInterface;
use Chill\MainBundle\Entity\User;
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use Psr\Log\NullLogger;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent;
use Symfony\Component\Messenger\Event\WorkerMessageHandledEvent;

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

    public function testThatNotGenerationMessageDoesNotCallAClearCache(): void
    {
        $storedObjectManager = $this->prophesize(StoredObjectManagerInterface::class);
        $storedObjectManager->clearCache()->shouldNotBeCalled();

        $eventSubscriber = $this->buildEventSubscriber($storedObjectManager->reveal());

        $eventSubscriber->afterHandling($this->buildEventSuccess(new \stdClass()));
        $eventSubscriber->afterFails($this->buildEventFailed(new \stdClass()));
    }

    public function testThatConcernedEventCallAClearCache(): void
    {
        $storedObjectManager = $this->prophesize(StoredObjectManagerInterface::class);
        $storedObjectManager->clearCache()->shouldBeCalledTimes(2);

        $eventSubscriber = $this->buildEventSubscriber($storedObjectManager->reveal());

        $eventSubscriber->afterHandling($this->buildEventSuccess($this->buildRequestGenerationMessage()));
        $eventSubscriber->afterFails($this->buildEventFailed($this->buildRequestGenerationMessage()));
    }

    private function buildRequestGenerationMessage(
    ): RequestGenerationMessage {
        $creator = new User();
        $creator->setEmail('fake@example.com');

        $class = new \ReflectionClass($creator);
        $property = $class->getProperty('id');
        $property->setAccessible(true);
        $property->setValue($creator, 1);

        $template ??= new DocGeneratorTemplate();
        $class = new \ReflectionClass($template);
        $property = $class->getProperty('id');
        $property->setAccessible(true);
        $property->setValue($template, 2);

        $destinationStoredObject = new StoredObject();
        $class = new \ReflectionClass($destinationStoredObject);
        $property = $class->getProperty('id');
        $property->setAccessible(true);
        $property->setValue($destinationStoredObject, 3);

        return new RequestGenerationMessage(
            $creator,
            $template,
            1,
            $destinationStoredObject,
            [],
        );
    }

    private function buildEventSubscriber(StoredObjectManagerInterface $storedObjectManager): OnAfterMessageHandledClearStoredObjectCache
    {
        return new OnAfterMessageHandledClearStoredObjectCache($storedObjectManager, new NullLogger());
    }

    private function buildEventFailed(object $message): WorkerMessageFailedEvent
    {
        $envelope = new Envelope($message);

        return new WorkerMessageFailedEvent($envelope, 'testing', new \RuntimeException());
    }

    private function buildEventSuccess(object $message): WorkerMessageHandledEvent
    {
        $envelope = new Envelope($message);

        return new WorkerMessageHandledEvent($envelope, 'test_receiver');
    }
}
