<?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\DocStoreBundle\Tests\Serializer\Normalizer;

use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Repository\StoredObjectRepositoryInterface;
use Chill\DocStoreBundle\Serializer\Normalizer\StoredObjectDenormalizer;
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;

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

    public function testDenormalizeWithoutObjectToPopulateWithUUID(): void
    {
        $storedObject = new StoredObject();

        $storedObjectRepository = $this->prophesize(StoredObjectRepositoryInterface::class);
        $storedObjectRepository->findOneByUUID($uuid = $storedObject->getUUID()->toString())
            ->shouldBeCalledOnce()
            ->willReturn($storedObject);

        $denormalizer = new StoredObjectDenormalizer($storedObjectRepository->reveal());

        $actual = $denormalizer->denormalize(['uuid' => $uuid], 'json');

        self::assertSame($storedObject, $actual);
    }

    public function testDenormalizeWithoutObjectToPopulateWithId(): void
    {
        $storedObject = new StoredObject();

        $storedObjectRepository = $this->prophesize(StoredObjectRepositoryInterface::class);
        $storedObjectRepository->find($id = 1)
            ->shouldBeCalledOnce()
            ->willReturn($storedObject);

        $denormalizer = new StoredObjectDenormalizer($storedObjectRepository->reveal());

        $actual = $denormalizer->denormalize(['id' => $id], 'json');

        self::assertSame($storedObject, $actual);
    }

    public function testDenormalizeTitle(): void
    {
        $storedObject = new StoredObject();
        $storedObject->setTitle('foo');

        $storedObjectRepository = $this->prophesize(StoredObjectRepositoryInterface::class);

        $denormalizer = new StoredObjectDenormalizer($storedObjectRepository->reveal());

        $actual = $denormalizer->denormalize([], StoredObject::class, 'json', [AbstractNormalizer::OBJECT_TO_POPULATE => $storedObject]);

        self::assertEquals('foo', $actual->getTitle(), 'the title should remains the same');

        $actual = $denormalizer->denormalize(['title' => 'bar'], StoredObject::class, 'json', [AbstractNormalizer::OBJECT_TO_POPULATE => $storedObject]);

        self::assertEquals('bar', $actual->getTitle(), 'the title should have been updated');
    }

    public function testDenormalizeNoNewVersion(): void
    {
        $storedObject = new StoredObject();
        $version = $storedObject->registerVersion();
        $iv = $version->getIv();
        $keyInfos = $version->getKeyInfos();
        $type = $version->getType();
        $filename = $version->getFilename();

        $storedObjectRepository = $this->prophesize(StoredObjectRepositoryInterface::class);

        $denormalizer = new StoredObjectDenormalizer($storedObjectRepository->reveal());

        $actual = $denormalizer->denormalize([
            'currentVersion' => [
                'iv' => $iv,
                'keyInfos' => $keyInfos,
                'type' => $type,
                'filename' => $filename,
            ],
        ], StoredObject::class, 'json', [AbstractNormalizer::OBJECT_TO_POPULATE => $storedObject]);

        self::assertSame($storedObject, $actual);
        self::assertSame($version, $storedObject->getCurrentVersion());
        self::assertEquals($iv, $version->getIv());
        self::assertEquals($keyInfos, $version->getKeyInfos());
        self::assertEquals($type, $version->getType());
        self::assertEquals($filename, $version->getFilename());
    }

    public function testDenormalizeNewVersion(): void
    {
        $storedObject = new StoredObject();
        $version = $storedObject->registerVersion();
        $iv = ['1, 2, 3'];
        $keyInfos = ['some-key' => 'some'];
        $type = 'text/html';
        $filename = 'Foo-Bar';

        $storedObjectRepository = $this->prophesize(StoredObjectRepositoryInterface::class);

        $denormalizer = new StoredObjectDenormalizer($storedObjectRepository->reveal());

        $actual = $denormalizer->denormalize([
            'currentVersion' => [
                'iv' => $iv,
                'keyInfos' => $keyInfos,
                'type' => $type,
                'filename' => $filename,
                // this is the required key for new versions
                'persisted' => false,
            ],
        ], StoredObject::class, 'json', [AbstractNormalizer::OBJECT_TO_POPULATE => $storedObject]);

        self::assertSame($storedObject, $actual);
        self::assertNotSame($version, $storedObject->getCurrentVersion());

        $version = $storedObject->getCurrentVersion();

        self::assertEquals($iv, $version->getIv());
        self::assertEquals($keyInfos, $version->getKeyInfos());
        self::assertEquals($type, $version->getType());
        self::assertEquals($filename, $version->getFilename());
    }
}
