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

use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Export\ExportConfigNormalizer;
use Chill\MainBundle\Export\ExportConfigProcessor;
use Chill\MainBundle\Export\ExportDescriptionHelper;
use Chill\MainBundle\Export\ExportGenerationContext;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\ExportManager;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Psr\Log\NullLogger;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Security;
use Symfony\Contracts\Translation\TranslatableInterface;
use Symfony\Contracts\Translation\TranslatorInterface;

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

    private const JSON_HAPPY_SCENARIO = <<<'JSON'
        {
          "export": {
            "form": [],
            "version": 1
          },
          "centers": {
            "centers": [
              1
            ],
            "regroupments": []
          },
          "filters": {
            "my_filter_string": {
              "form": {
                "accepted_socialissues": [
                  2,
                  3
                ]
              },
              "enabled": true,
              "version": 1
            },
            "my_filter_array": {
              "form": {
                "misc": true
              },
              "enabled": true,
              "version": 1
            },
            "my_filter_translatable": {
              "form": {
                "misc": true
              },
              "enabled": true,
              "version": 1
            }
          },
          "formatter": {
            "form": {
              "format": "xlsx",
              "activity_user_aggregator": {
                "order": 1
              }
            },
            "version": 1
          },
          "aggregators": {
            "my_aggregator": {
              "form": {"key": 1},
              "enabled": true,
              "version": 1
            }
          },
          "pick_formatter": "spreadsheet"
        }
        JSON;

    public function testDescribeHappyScenario(): void
    {
        $options = json_decode(self::JSON_HAPPY_SCENARIO, true);

        $security = $this->prophesize(Security::class);
        $security->getUser()->willReturn($user = new User());

        $exportConfigNormalizer = $this->prophesize(ExportConfigNormalizer::class);
        $exportConfigNormalizer->denormalizeConfig('my_export', Argument::type('array'))->willReturn($options);

        $export = $this->prophesize(ExportInterface::class);
        $export->getTitle()->willReturn('Title');

        $myFilterString = $this->prophesize(FilterInterface::class);
        $myFilterString->describeAction(Argument::type('array'), Argument::type(ExportGenerationContext::class))->willReturn($string0 = 'This is a filter description');
        $myFilterArray = $this->prophesize(FilterInterface::class);
        $myFilterArray->describeAction(Argument::type('array'), Argument::type(ExportGenerationContext::class))->willReturn([$string1 = 'This is a filter with %argument%', $arg1 = ['%argument%' => 'zero']]);
        $myFilterTranslatable = $this->prophesize(FilterInterface::class);
        $myFilterTranslatable->describeAction(Argument::type('array'), Argument::type(ExportGenerationContext::class))
            ->willReturn(new class () implements TranslatableInterface {
                public function trans(TranslatorInterface $translator, ?string $locale = null): string
                {
                    return 'translatable';
                }
            });

        $myAggregator = $this->prophesize(AggregatorInterface::class);
        $myAggregator->getTitle()->willReturn('Some aggregator');

        $token = new UsernamePasswordToken($user, 'main', ['ROLE_USER']);
        $tokenStorage = new TokenStorage();
        $tokenStorage->setToken($token);

        $exportManager = new ExportManager(
            new NullLogger(),
            $security->reveal(),
            $this->prophesize(AuthorizationHelperInterface::class)->reveal(),
            $tokenStorage,
            ['my_export' => $export->reveal()],
            ['my_aggregator' => $myAggregator->reveal()],
            [
                'my_filter_string' => $myFilterString->reveal(),
                'my_filter_array' => $myFilterArray->reveal(),
                'my_filter_translatable' => $myFilterTranslatable->reveal(),
            ],
            [],
        );

        $exportConfigProcessor = new ExportConfigProcessor($exportManager);

        $translator = $this->prophesize(TranslatorInterface::class);
        $translator->trans('Title')->shouldBeCalled()->willReturn('Title');
        $translator->trans($string0)->shouldBeCalled()->willReturn($string0);
        $translator->trans($string1, $arg1)->shouldBeCalled()->willReturn($string1);
        $translator->trans('Some aggregator')->shouldBeCalled()->willReturn('Some aggregator');

        $exportDescriptionHelper = new ExportDescriptionHelper(
            $exportManager,
            $exportConfigNormalizer->reveal(),
            $exportConfigProcessor,
            $translator->reveal(),
            $security->reveal(),
        );

        $actual = $exportDescriptionHelper->describe('my_export', $options);

        self::assertIsArray($actual);
        self::assertEquals($actual[0], 'Title');
        self::assertEquals($actual[1], 'This is a filter description');
        self::assertEquals($actual[2], 'This is a filter with %argument%');
        self::assertEquals($actual[3], 'translatable');
        self::assertEquals($actual[4], 'Some aggregator');
    }
}
