<?php declare(strict_types=1);

namespace Newland\Toubiz\Poi\Neos\Tests\Unit\DataSource;

use Neos\Flow\Tests\FunctionalTestCase;
use Newland\NeosTestingHelpers\InteractsWithNodes;
use Newland\Toubiz\Api\ObjectAdapter\Concern\ArticleConstants;
use Newland\Toubiz\Poi\Neos\DataSource\CategoriesDataSource;
use Newland\Toubiz\Sync\Neos\Domain\Repository\CategoryRepository;
use Newland\Toubiz\Sync\Neos\Tests\Factory\ArticleFactory;
use Newland\Toubiz\Sync\Neos\Tests\Factory\CategoryFactory;

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

    /** @var ArticleFactory */
    protected $articleFactory;

    /** @var CategoryFactory */
    protected $categoryFactory;

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

    public function setUp(): void
    {
        parent::setUp();
        $this->articleFactory = new ArticleFactory($this->objectManager);
        $this->categoryFactory = new CategoryFactory($this->objectManager);
        $this->subject = $this->objectManager->get(CategoriesDataSource::class);
    }

    public function testFindsCategoriesRelatedToArticles(): void
    {
        [ $withRelations ] = $this->categoryFactory->createMultiple(2);
        $this->articleFactory->create([ 'categories' => [ $withRelations ] ]);

        $result = $this->subject->getData();
        $this->assertCount(1, $result);
        $this->assertEquals($withRelations->getPersistenceObjectIdentifier(), $result[0]['value']);
    }

    public function testFindsOnlyCategoriesRelatedToArticlesIfPassedThroughArguments(): void
    {
        [ $relatedToTour, $relatedToGastro, $relatedToBoth ] = $this->categoryFactory->createMultiple(4);
        $this->articleFactory->create(
            [
                'mainType' => ArticleConstants::TYPE_TOUR,
                'categories' => [ $relatedToTour, $relatedToBoth ],
            ]
        );
        $this->articleFactory->create(
            [
                'mainType' => ArticleConstants::TYPE_GASTRONOMY,
                'categories' => [ $relatedToGastro, $relatedToBoth ],
            ]
        );

        $result = $this->subject->getData(null, [ 'articleType' => ArticleConstants::TYPE_TOUR ]);
        $this->assertCount(2, $result);

        $result = $this->subject->getData(null, [ 'articleType' => ArticleConstants::TYPE_GASTRONOMY ]);
        $this->assertCount(2, $result);

        $result = $this->subject->getData(null, [ 'articleType' => ArticleConstants::TYPE_CITY ]);
        $this->assertCount(0, $result);
    }

    public function testFindsOnlyCategoriesRelatedToArticlesIfPassedThroughNodeProperties(): void
    {
        [ $relatedToTour, $relatedToGastro, $relatedToBoth ] = $this->categoryFactory->createMultiple(4);
        $this->articleFactory->create(
            [
                'mainType' => ArticleConstants::TYPE_TOUR,
                'categories' => [ $relatedToTour, $relatedToBoth ],
            ]
        );
        $this->articleFactory->create(
            [
                'mainType' => ArticleConstants::TYPE_GASTRONOMY,
                'categories' => [ $relatedToGastro, $relatedToBoth ],
            ]
        );

        $node = $this->initializeNode('/sites/foo-bar', null, null, [], 'de');

        $node->setProperty('articleType', ArticleConstants::TYPE_TOUR);
        $result = $this->subject->getData($node);
        $this->assertCount(2, $result);

        $node->setProperty('articleType', ArticleConstants::TYPE_GASTRONOMY);
        $result = $this->subject->getData($node);
        $this->assertCount(2, $result);

        $node->setProperty('articleType', ArticleConstants::TYPE_CITY);
        $result = $this->subject->getData($node);
        $this->assertCount(0, $result);
    }

    public function testGetsLanguageFromCurrentNode(): void
    {
        $german = $this->categoryFactory->create([ 'language' => 'de' ]);
        $english = $this->categoryFactory->create([ 'language' => 'en' ]);
        $this->articleFactory->create([ 'language' => 'de', 'categories' => [ $german ] ]);
        $this->articleFactory->create([ 'language' => 'en', 'categories' => [ $english ] ]);

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


        $node = $this->initializeNode('/sites/foo-baz', null, null, [], 'en');
        $result = $this->subject->getData($node);
        $this->assertCount(1, $result);
        $this->assertEquals($english->getPersistenceObjectIdentifier(), $result[0]['value']);
    }

    public function testDoesNotTaintRepository(): void
    {
        $repository = $this->objectManager->get(CategoryRepository::class);
        $repository->setLanguage('de');

        $node = $this->initializeNode('/sites/foo-baz', null, null, [], 'en');
        $this->subject->getData($node);

        $this->assertEquals('de', $repository->getLanguage());
    }
}
