<?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\Center;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Export\ExportConfigNormalizer;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\ExportManager;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Repository\CenterRepositoryInterface;
use Chill\MainBundle\Repository\RegroupmentRepositoryInterface;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;

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

    public function testNormalizeConfig(): void
    {
        $filterEnabled = $this->prophesize(FilterInterface::class);
        $filterEnabled->normalizeFormData(['test' => '0'])->shouldBeCalled()->willReturn(['test' => '0']);
        $filterEnabled->getNormalizationVersion()->willReturn(1);
        $filterDisabled = $this->prophesize(FilterInterface::class);
        $filterDisabled->normalizeFormData(['default' => '0'])->shouldNotBeCalled();

        $aggregatorEnabled = $this->prophesize(AggregatorInterface::class);
        $aggregatorEnabled->normalizeFormData(['test' => '0'])->shouldBeCalled()->willReturn(['test' => '0']);
        $aggregatorEnabled->getNormalizationVersion()->willReturn(1);
        $aggregatorDisabled = $this->prophesize(AggregatorInterface::class);
        $aggregatorDisabled->normalizeFormData(['default' => '0'])->shouldNotBeCalled();

        $export = $this->prophesize(ExportInterface::class);
        $export->normalizeFormData(['test' => '0'])->shouldBeCalled()->willReturn(['test' => '0']);
        $export->getNormalizationVersion()->willReturn(1);

        $formatter = $this->prophesize(FormatterInterface::class);
        $formatter->normalizeFormData(['test' => '0'])->shouldBeCalled()->willReturn(['test' => '0']);
        $formatter->getNormalizationVersion()->willReturn(1);

        $exportManager = $this->prophesize(ExportManager::class);
        $exportManager->getFormatter('xlsx')->shouldBeCalled()->willReturn($formatter->reveal());
        $exportManager->getFilter('filterEnabled')->willReturn($filterEnabled->reveal());
        $exportManager->getFilter('filterDisabled')->willReturn($filterDisabled->reveal());
        $exportManager->getAggregator('aggregatorEnabled')->willReturn($aggregatorEnabled->reveal());
        $exportManager->getAggregator('aggregatorDisabled')->willReturn($aggregatorDisabled->reveal());
        $exportManager->getExport('export')->willReturn($export->reveal());

        $regroupmentRepository = $this->prophesize(RegroupmentRepositoryInterface::class);

        $center = $this->prophesize(Center::class);
        $center->getId()->willReturn(10);

        $formData = [
            'centers' => ['centers' => [$center->reveal()]],
            'export' => ['test' => '0'],
            'filters' => [
                'filterEnabled' => ['enabled' => true, 'form' => ['test' => '0']],
                'filterDisabled' => ['enabled' => false, 'form' => ['default' => '0']],
            ],
            'aggregators' => [
                'aggregatorEnabled' => ['enabled' => true, 'form' => ['test' => '0']],
                'aggregatorDisabled' => ['enabled' => false, 'form' => ['default' => '0']],
            ],
            'pick_formatter' => 'xlsx',
            'formatter' => ['test' => '0'],
        ];

        $expected = [
            'export' => ['form' => ['test' => '0'], 'version' => 1],
            'centers' => ['centers' => [10], 'regroupments' => []],
            'filters' => [
                'filtersEnabled' => ['enabled' => true, 'form' => ['test' => '0'], 'version' => 1],
                'filterDisabled' => ['enabled' => false],
            ],
            'aggregators' => [
                'aggregatorEnabled' => ['enabled' => true, 'form' => ['test' => '0'], 'version' => 1],
                'aggregatorDisabled' => ['enabled' => false],
            ],
            'pick_formatter' => 'xlsx',
            'formatter' => [
                'form' => ['test' => '0'],
                'version' => 1,
            ],
        ];

        $exportConfigNormalizer = new ExportConfigNormalizer(
            $exportManager->reveal(),
            $this->prophesize(CenterRepositoryInterface::class)->reveal(),
            $regroupmentRepository->reveal()
        );

        $actual = $exportConfigNormalizer->normalizeConfig('export', $formData);

        self::assertEqualsCanonicalizing($expected, $actual);
    }

    public function testDenormalizeConfig(): void
    {
        $filterEnabled = $this->prophesize(FilterInterface::class);
        $filterEnabled->denormalizeFormData(['test' => '0'], 1)->shouldBeCalled()->willReturn(['test' => '0']);
        $filterDisabled = $this->prophesize(FilterInterface::class);
        $filterDisabled->denormalizeFormData(Argument::any(), Argument::type('int'))->shouldNotBeCalled();
        $filterDisabled->getFormDefaultData()->willReturn(['default' => '0']);

        $aggregatorEnabled = $this->prophesize(AggregatorInterface::class);
        $aggregatorEnabled->denormalizeFormData(['test' => '0'], 1)->shouldBeCalled()->willReturn(['test' => '0']);
        $aggregatorDisabled = $this->prophesize(AggregatorInterface::class);
        $aggregatorDisabled->denormalizeFormData(Argument::any(), Argument::type('int'))->shouldNotBeCalled();
        $aggregatorDisabled->getFormDefaultData()->willReturn(['default' => '0']);

        $export = $this->prophesize(ExportInterface::class);
        $export->denormalizeFormData(['test' => '0'], 1)->shouldBeCalled()->willReturn(['test' => '0']);

        $formatter = $this->prophesize(FormatterInterface::class);
        $formatter->denormalizeFormData(['test' => '0'], 1)->shouldBeCalled()->willReturn(['test' => '0']);

        $exportManager = $this->prophesize(ExportManager::class);
        $exportManager->getFormatter('xlsx')->shouldBeCalled()->willReturn($formatter->reveal());
        $exportManager->getFilter('filterEnabled')->willReturn($filterEnabled->reveal());
        $exportManager->getFilter('filterDisabled')->willReturn($filterDisabled->reveal());
        $exportManager->getAggregator('aggregatorEnabled')->willReturn($aggregatorEnabled->reveal());
        $exportManager->getAggregator('aggregatorDisabled')->willReturn($aggregatorDisabled->reveal());
        $exportManager->getExport('export')->willReturn($export->reveal());

        $centerRepository = $this->prophesize(CenterRepositoryInterface::class);
        $centerRepository->find(10)->willReturn($center = new Center());

        $regroupmentRepository = $this->prophesize(RegroupmentRepositoryInterface::class);

        $serialized = [
            'centers' => ['regroupments' => [], 'centers' => [10]],
            'export' => ['form' => ['test' => '0'], 'version' => 1],
            'filters' => [
                'filterEnabled' => ['enabled' => true, 'form' => ['test' => '0'], 'version' => 1],
                'filterDisabled' => ['enabled' => false],
            ],
            'aggregators' => [
                'aggregatorEnabled' => ['enabled' => true, 'form' => ['test' => '0'], 'version' => 1],
                'aggregatorDisabled' => ['enabled' => false],
            ],
            'pick_formatter' => 'xlsx',
            'formatter' => [
                'form' => ['test' => '0'],
                'version' => 1,
            ],
        ];

        $expected = [
            'export' => ['test' => '0'],
            'filters' => [
                'filterEnabled' => ['enabled' => true, 'form' => ['test' => '0']],
                'filterDisabled' => ['enabled' => false, 'form' => ['default' => '0']],
            ],
            'aggregators' => [
                'aggregatorEnabled' => ['enabled' => true, 'form' => ['test' => '0']],
                'aggregatorDisabled' => ['enabled' => false, 'form' => ['default' => '0']],
            ],
            'pick_formatter' => 'xlsx',
            'formatter' => ['test' => '0'],
            'centers' => ['centers' => [$center], 'regroupments' => []],
        ];

        $exportConfigNormalizer = new ExportConfigNormalizer($exportManager->reveal(), $centerRepository->reveal(), $regroupmentRepository->reveal());
        $actual = $exportConfigNormalizer->denormalizeConfig('export', $serialized, true);

        self::assertEquals($expected, $actual);
    }

    public function testNormalizeConfigEmptyData(): void
    {
        $filterEnabled = $this->prophesize(FilterInterface::class);
        $filterEnabled->normalizeFormData([])->shouldBeCalled()->willReturn([]);
        $filterEnabled->getNormalizationVersion()->willReturn(1);
        $filterDisabled = $this->prophesize(FilterInterface::class);
        $filterDisabled->normalizeFormData([])->shouldNotBeCalled();

        $aggregatorEnabled = $this->prophesize(AggregatorInterface::class);
        $aggregatorEnabled->normalizeFormData([])->shouldBeCalled()->willReturn([]);
        $aggregatorEnabled->getNormalizationVersion()->willReturn(1);
        $aggregatorDisabled = $this->prophesize(AggregatorInterface::class);
        $aggregatorDisabled->normalizeFormData([])->shouldNotBeCalled();

        $export = $this->prophesize(ExportInterface::class);
        $export->normalizeFormData([])->shouldBeCalled()->willReturn([]);
        $export->getNormalizationVersion()->willReturn(1);

        $formatter = $this->prophesize(FormatterInterface::class);
        $formatter->normalizeFormData([])->shouldBeCalled()->willReturn([]);
        $formatter->getNormalizationVersion()->willReturn(1);

        $exportManager = $this->prophesize(ExportManager::class);
        $exportManager->getFormatter('xlsx')->shouldBeCalled()->willReturn($formatter->reveal());
        $exportManager->getFilter('filterEnabled')->willReturn($filterEnabled->reveal());
        $exportManager->getFilter('filterDisabled')->willReturn($filterDisabled->reveal());
        $exportManager->getAggregator('aggregatorEnabled')->willReturn($aggregatorEnabled->reveal());
        $exportManager->getAggregator('aggregatorDisabled')->willReturn($aggregatorDisabled->reveal());
        $exportManager->getExport('export')->willReturn($export->reveal());

        $center = $this->prophesize(Center::class);
        $center->getId()->willReturn(10);

        $regroupmentRepository = $this->prophesize(RegroupmentRepositoryInterface::class);

        $formData = [
            'centers' => ['centers' => [$center->reveal()]],
            'export' => [],
            'filters' => [
                'filterEnabled' => ['enabled' => true, 'form' => []],
                'filterDisabled' => ['enabled' => false, 'form' => []],
            ],
            'aggregators' => [
                'aggregatorEnabled' => ['enabled' => true, 'form' => []],
                'aggregatorDisabled' => ['enabled' => false, 'form' => []],
            ],
            'pick_formatter' => 'xlsx',
            'formatter' => [],
        ];

        $expected = [
            'export' => ['form' => [], 'version' => 1],
            'centers' => ['centers' => [10], 'regroupments' => []],
            'filters' => [
                'filtersEnabled' => ['enabled' => true, 'form' => [], 'version' => 1],
                'filterDisabled' => ['enabled' => false],
            ],
            'aggregators' => [
                'aggregatorEnabled' => ['enabled' => true, 'form' => [], 'version' => 1],
                'aggregatorDisabled' => ['enabled' => false],
            ],
            'pick_formatter' => 'xlsx',
            'formatter' => [
                'form' => [],
                'version' => 1,
            ],
        ];

        $exportConfigNormalizer = new ExportConfigNormalizer($exportManager->reveal(), $this->prophesize(CenterRepositoryInterface::class)->reveal(), $regroupmentRepository->reveal());

        $actual = $exportConfigNormalizer->normalizeConfig('export', $formData);

        self::assertEqualsCanonicalizing($expected, $actual);
    }

    public function testDenormalizeConfigWithEmptyData(): void
    {
        $filterEnabled = $this->prophesize(FilterInterface::class);
        $filterEnabled->denormalizeFormData([], 1)->shouldBeCalled()->willReturn([]);
        $filterDisabled = $this->prophesize(FilterInterface::class);
        $filterDisabled->denormalizeFormData(Argument::any(), Argument::type('int'))->shouldNotBeCalled();
        $filterDisabled->getFormDefaultData()->willReturn([]);

        $aggregatorEnabled = $this->prophesize(AggregatorInterface::class);
        $aggregatorEnabled->denormalizeFormData([], 1)->shouldBeCalled()->willReturn([]);
        $aggregatorDisabled = $this->prophesize(AggregatorInterface::class);
        $aggregatorDisabled->denormalizeFormData(Argument::any(), Argument::type('int'))->shouldNotBeCalled();
        $aggregatorDisabled->getFormDefaultData()->willReturn([]);

        $export = $this->prophesize(ExportInterface::class);
        $export->denormalizeFormData([], 1)->shouldBeCalled()->willReturn([]);

        $formatter = $this->prophesize(FormatterInterface::class);
        $formatter->denormalizeFormData([], 1)->shouldBeCalled()->willReturn([]);

        $exportManager = $this->prophesize(ExportManager::class);
        $exportManager->getFormatter('xlsx')->shouldBeCalled()->willReturn($formatter->reveal());
        $exportManager->getFilter('filterEnabled')->willReturn($filterEnabled->reveal());
        $exportManager->getFilter('filterDisabled')->willReturn($filterDisabled->reveal());
        $exportManager->getAggregator('aggregatorEnabled')->willReturn($aggregatorEnabled->reveal());
        $exportManager->getAggregator('aggregatorDisabled')->willReturn($aggregatorDisabled->reveal());
        $exportManager->getExport('export')->willReturn($export->reveal());

        $centerRepository = $this->prophesize(CenterRepositoryInterface::class);
        $centerRepository->find(10)->willReturn($center = new Center());

        $regroupmentRepository = $this->prophesize(RegroupmentRepositoryInterface::class);

        $serialized = [
            'centers' => ['centers' => [10], 'regroupments' => []],
            'export' => ['form' => [], 'version' => 1],
            'filters' => [
                'filterEnabled' => ['enabled' => true, 'form' => [], 'version' => 1],
                'filterDisabled' => ['enabled' => false],
            ],
            'aggregators' => [
                'aggregatorEnabled' => ['enabled' => true, 'form' => [], 'version' => 1],
                'aggregatorDisabled' => ['enabled' => false],
            ],
            'pick_formatter' => 'xlsx',
            'formatter' => [
                'form' => [],
                'version' => 1,
            ],
        ];

        $expected = [
            'export' => [],
            'filters' => [
                'filterEnabled' => ['enabled' => true, 'form' => []],
                'filterDisabled' => ['enabled' => false, 'form' => []],
            ],
            'aggregators' => [
                'aggregatorEnabled' => ['enabled' => true, 'form' => []],
                'aggregatorDisabled' => ['enabled' => false, 'form' => []],
            ],
            'pick_formatter' => 'xlsx',
            'formatter' => [],
            'centers' => ['centers' => [$center], 'regroupments' => []],
        ];

        $exportConfigNormalizer = new ExportConfigNormalizer($exportManager->reveal(), $centerRepository->reveal(), $regroupmentRepository->reveal());
        $actual = $exportConfigNormalizer->denormalizeConfig('export', $serialized, true);

        self::assertEquals($expected, $actual);
    }
}
