<?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\Entity\Center;
use Chill\MainBundle\Entity\Civility;
use Chill\MainBundle\Entity\Location;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\UserJob;
use Chill\MainBundle\Serializer\Normalizer\UserNormalizer;
use Chill\MainBundle\Templating\Entity\UserRender;
use libphonenumber\NumberParseException;
use libphonenumber\PhoneNumber;
use libphonenumber\PhoneNumberUtil;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Symfony\Component\Clock\MockClock;
use Symfony\Component\Serializer\Exception\ExceptionInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;

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

    /**
     * @dataProvider dataProviderUserNormalizer
     *
     * @throws ExceptionInterface
     */
    public function testNormalize(?User $user, mixed $format, mixed $context, mixed $expected)
    {
        $userRender = $this->prophesize(UserRender::class);
        $userRender->renderString(Argument::type(User::class), Argument::type('array'))->willReturn($user ? $user->getLabel() : '');

        $clock = new MockClock(new \DateTimeImmutable('now'));

        $normalizer = new UserNormalizer($userRender->reveal(), $clock);
        $normalizer->setNormalizer(new class () implements NormalizerInterface {
            public function normalize($object, ?string $format = null, array $context = [])
            {
                return ['context' => $context['docgen:expects'] ?? null];
            }

            public function supportsNormalization($data, ?string $format = null)
            {
                return true;
            }
        });

        $this->assertEquals($expected, $normalizer->normalize($user, $format, $context));
    }

    /**
     * @throws NumberParseException
     */
    public static function dataProviderUserNormalizer()
    {
        $user = new User();
        $userNoPhone = new User();

        $user
            ->setUsername('SomeUser')
            ->setLabel('SomeUser')
            ->setPhonenumber(PhoneNumberUtil::getInstance()->parse('+32475928635'))
            ->setEmail('some.user@chill.com');

        $userNoPhone
            ->setUsername('AnotherUser')
            ->setLabel('AnotherUser');

        yield [$user, 'docgen', ['docgen:expects' => User::class],
            [
                'id' => $user->getId(), // id
                'type' => 'user', // type
                'username' => 'SomeUser', // username
                'email' => 'some.user@chill.com', // email
                'text' => 'SomeUser', // text
                'label' => 'SomeUser', // label
                'phonenumber' => ['context' => PhoneNumber::class], // phonenumber
                'main_scope' => ['context' => Scope::class], // scope
                'user_job' => ['context' => UserJob::class], // user job
                'current_location' => ['context' => Location::class], // curent location
                'main_location' => ['context' => Location::class], // main location
                'civility' => ['context' => Civility::class], // civility
                'text_without_absent' => 'SomeUser',
                'isAbsent' => false,
                'main_center' => ['context' => Center::class],
                'absenceStart' => ['context' => \DateTimeImmutable::class],
                'absenceEnd' => ['context' => \DateTimeImmutable::class],
                'enabled' => true,
            ]];

        yield [$userNoPhone, 'docgen', ['docgen:expects' => User::class],
            [
                'id' => $user->getId(), // id
                'type' => 'user', // type
                'username' => 'AnotherUser', // username
                'email' => '', // email
                'text' => 'AnotherUser', // text
                'label' => 'AnotherUser', // label
                'phonenumber' => ['context' => PhoneNumber::class], // phonenumber
                'main_scope' => ['context' => Scope::class], // scope
                'user_job' => ['context' => UserJob::class], // user job
                'current_location' => ['context' => Location::class], // curent location
                'main_location' => ['context' => Location::class], // main location
                'civility' => ['context' => Civility::class], // civility
                'text_without_absent' => 'AnotherUser',
                'isAbsent' => false,
                'main_center' => ['context' => Center::class],
                'absenceStart' => ['context' => \DateTimeImmutable::class],
                'absenceEnd' => ['context' => \DateTimeImmutable::class],
                'enabled' => true,
            ]];

        yield [null, 'docgen', ['docgen:expects' => User::class], [
            'id' => '', // id
            'type' => 'user', // type
            'username' => '', // username
            'email' => '', // email
            'text' => '', // text
            'label' => '', // label
            'phonenumber' => ['context' => PhoneNumber::class], // phonenumber
            'main_scope' => ['context' => Scope::class], // scope
            'user_job' => ['context' => UserJob::class], // user job
            'current_location' => ['context' => Location::class], // curent location
            'main_location' => ['context' => Location::class], // main location
            'civility' => ['context' => Civility::class], // civility
            'text_without_absent' => '',
            'isAbsent' => false,
            'main_center' => ['context' => Center::class],
            'absenceStart' => null,
            'absenceEnd' => null,
            'enabled' => true,
        ]];
    }
}
