<?php declare(strict_types=1);

namespace Newland\NeosFiltering\Tests\Unit\DataSource;

use Neos\Flow\I18n\Translator;
use Neos\Flow\Tests\FunctionalTestCase;
use Newland\NeosFiltering\DataSource\DirectDataSource;
use Newland\NeosFiltering\Service\FilterDictionaryService;
use Newland\NeosTestingHelpers\InteractsWithNodes;

class DirectDataSourceTest extends FunctionalTestCase
{
    protected static $testablePersistenceEnabled = true;
    use InteractsWithNodes;

    /** @var DirectDataSource */
    protected $subject;

    /** @var FilterDictionaryService */
    protected $dictionaryService;

    public function setUp(): void
    {
        parent::setUp();
        $this->subject = new DirectDataSource();

        $this->dictionaryService = $this->objectManager->get(FilterDictionaryService::class);
        $this->inject($this->subject, 'filterDictionaryService', $this->dictionaryService);
    }

    public function testReturnsOptionsConfiguredInFilterGroups(): void
    {
        $this->setupFilterGroups(
            [
                'foo' => [
                    'items' => [
                        [ 'label' => 'Foo', 'value' => 'foo' ],
                        [ 'label' => 'Bar', 'value' => 'bar' ],
                    ],
                ],
            ]
        );
        $result = $this->subject->getData(null, [ 'filterGroup' => 'foo' ]);

        $this->assertCount(2, $result);
        $this->assertEquals('foo', $result[0]['value']);
        $this->assertEquals('bar', $result[1]['value']);
    }

    public function testFetchesLanguageLabelForOptions(): void
    {
        $translator = $this->createMock(Translator::class);
        $translator->expects($this->exactly(2))
            ->method('translateById')
            ->withConsecutive(
                [ 'foo', [], null, null, 'View/Filter', 'Newland.MyTheme' ],
                [ 'group.foo', [], null, null, null, null ]
            )
            ->willReturn('This is a test');


        $this->inject($this->dictionaryService, 'translator', $translator);

        $this->setupFilterGroups(
            [
                'foo' => [
                    'translations' => [
                        'i18n' => [
                            'package' => 'Newland.MyTheme',
                            'source' => 'View/Filter',
                        ],
                    ],
                    'sections' => [
                        'package' => 'Newland.MyTheme',
                        'source' => 'View/Filter',
                    ],
                    'items' => [
                        [ 'value' => 'foo' ],
                    ],
                ],
            ]
        );

        $result = $this->subject->getData(null, [ 'filterGroup' => 'foo' ]);

        $this->assertEquals('This is a test', $result[0]['label']);
    }

    public function testAllowsSpecifyingCustomLanguageLabelIdForOption(): void
    {
        $translator = $this->createMock(Translator::class);
        $translator->expects($this->exactly(2))
            ->method('translateById')
            ->withConsecutive(
                [ 'custom.property.foo', [], null, null, 'View/Filter', 'Newland.MyTheme' ],
                [ 'group.foo', [], null, null, null, null ]
            )
            ->willReturn('Custom property works');

        $this->inject($this->dictionaryService, 'translator', $translator);

        $this->setupFilterGroups(
            [
                'foo' => [
                    'translations' => [
                        'i18n' => [
                            'package' => 'Newland.MyTheme',
                            'source' => 'View/Filter',
                        ],
                    ],
                    'sections' => [
                        'package' => 'Newland.MyTheme',
                        'source' => 'View/Filter',
                    ],
                    'items' => [
                        [ 'value' => 'foo', 'i18n' => [ 'id' => 'custom.property.foo' ] ],
                    ],
                ],
            ]
        );

        $result = $this->subject->getData(null, [ 'filterGroup' => 'foo' ]);
        $this->assertEquals('Custom property works', $result[0]['label']);
    }

    public function testAllowsSpecifyingCustomI18nConfigurationForOption(): void
    {
        $translator = $this->createMock(Translator::class);
        $translator->expects($this->exactly(2))
            ->method('translateById')
            ->withConsecutive(
                [ 'custom.property.foo', [], null, null, 'View/Filter/Custom', 'Newland.MyOtherTheme' ],
                [ 'group.foo', [], null, null, null, null ]
            )
            ->willReturn('Custom property works');

        $this->inject($this->dictionaryService, 'translator', $translator);

        $this->setupFilterGroups(
            [
                'foo' => [
                    'translations' => [
                        'i18n' => [
                            'package' => 'Newland.MyTheme',
                            'source' => 'View/Filter',
                        ],
                    ],
                    'sections' => [
                        'package' => 'Newland.MyTheme',
                        'source' => 'View/Filter',
                    ],
                    'items' => [
                        [
                            'value' => 'foo',
                            'i18n' => [
                                'id' => 'custom.property.foo',
                                'package' => 'Newland.MyOtherTheme',
                                'source' => 'View/Filter/Custom',
                            ],
                        ],
                    ],
                ],
            ]
        );

        $result = $this->subject->getData(null, [ 'filterGroup' => 'foo' ]);
        $this->assertEquals('Custom property works', $result[0]['label']);
    }

    public function testUsesOptionsInCorrectLanguage(): void
    {
        $this->setupFilterGroups(
            [
                'foo' => [
                    'isLanguageAware' => true,
                    'items' => [
                        'en' => [ [ 'value' => 'english', 'label' => 'English' ] ],
                        'de' => [ [ 'value' => 'german', 'label' => 'German' ] ],
                    ],
                ],
            ]
        );

        $results = $this->subject->getData(
            $this->initializeNode('/sites/foo-bar', null, null, [], 'en'),
            [ 'filterGroup' => 'foo' ]
        );
        $this->assertCount(1, $results);
        $this->assertEquals('english', $results[0]['value']);

        $results = $this->subject->getData(
            $this->initializeNode('/sites/foo-bar', null, null, [], 'de'),
            [ 'filterGroup' => 'foo' ]
        );
        $this->assertCount(1, $results);
        $this->assertEquals('german', $results[0]['value']);

        $results = $this->subject->getData(
            $this->initializeNode('/sites/foo-bar', null, null, [], 'fr'),
            [ 'filterGroup' => 'foo' ]
        );
        $this->assertCount(0, $results);
    }

    private function setupFilterGroups(array $filterGroups): void
    {
        $this->inject($this->dictionaryService, 'filterGroups', $filterGroups);
    }

}
