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

use Chill\MainBundle\Serializer\Normalizer\DateNormalizer;
use Prophecy\Prophet;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;

/**
 * @internal
 *
 * @coversNothing
 */
final class DateNormalizerTest extends KernelTestCase
{
    private Prophet $prophet;

    protected function setUp(): void
    {
        $this->prophet = new Prophet();
    }

    /**
     * @dataProvider generateDataNormalize
     */
    public function testNormalize(mixed $expected, mixed $date, mixed $format, mixed $locale, mixed $msg)
    {
        $this->assertEquals($expected, $this->buildDateNormalizer($locale)->normalize($date, $format, []), $msg);
    }

    public static function generateDataNormalize()
    {
        $datetime = \DateTime::createFromFormat('Y-m-d H:i:sO', '2021-06-05 15:05:01+02:00');
        $date = \DateTime::createFromFormat('Y-m-d H:i:sO', '2021-06-05 00:00:00+02:00');

        yield [
            ['datetime' => '2021-06-05T15:05:01+0200', 'datetime8601' => '2021-06-05T15:05:01+02:00'],
            $datetime, 'json', null, 'simple normalization to json',
        ];

        yield [
            ['long' => '5 juin 2021', 'short' => '05/06/2021'],
            $date, 'docgen', 'fr', 'normalization to docgen for a date, with current request',
        ];

        yield [
            ['long' => '5 juin 2021', 'short' => '05/06/2021'],
            $date, 'docgen', null, 'normalization to docgen for a date, without current request',
        ];

        yield [
            ['long' => '5 juin 2021 à 15:05', 'short' => '05/06/2021 15:05'],
            $datetime, 'docgen', null, 'normalization to docgen for a datetime, without current request',
        ];

        yield [
            ['long' => '', 'short' => ''],
            null, 'docgen', null, 'normalization to docgen for a null datetime',
        ];
    }

    public function testSupports()
    {
        $this->assertTrue($this->buildDateNormalizer()->supportsNormalization(new \DateTime(), 'json'));
        $this->assertTrue($this->buildDateNormalizer()->supportsNormalization(new \DateTimeImmutable(), 'json'));
        $this->assertTrue($this->buildDateNormalizer()->supportsNormalization(new \DateTime(), 'docgen'));
        $this->assertTrue($this->buildDateNormalizer()->supportsNormalization(new \DateTimeImmutable(), 'docgen'));
        $this->assertTrue($this->buildDateNormalizer()->supportsNormalization(null, 'docgen', ['docgen:expects' => \DateTimeImmutable::class]));
        $this->assertTrue($this->buildDateNormalizer()->supportsNormalization(null, 'docgen', ['docgen:expects' => \DateTimeInterface::class]));
        $this->assertTrue($this->buildDateNormalizer()->supportsNormalization(null, 'docgen', ['docgen:expects' => \DateTime::class]));
        $this->assertFalse($this->buildDateNormalizer()->supportsNormalization(new \stdClass(), 'docgen'));
        $this->assertFalse($this->buildDateNormalizer()->supportsNormalization(new \DateTime(), 'xml'));
    }

    private function buildDateNormalizer(?string $locale = null): DateNormalizer
    {
        $requestStack = $this->prophet->prophesize(RequestStack::class);
        $parameterBag = new ParameterBag();
        $parameterBag->set('kernel.default_locale', 'fr');

        if (null === $locale) {
            $requestStack->getCurrentRequest()->willReturn(null);
        } else {
            $request = $this->prophet->prophesize(Request::class);
            $request->getLocale()->willReturn($locale);
            $requestStack->getCurrentRequest()->willReturn($request->reveal());
        }

        return new DateNormalizer($requestStack->reveal(), $parameterBag);
    }
}
