<?php declare(strict_types=1);

namespace Newland\Toubiz\Poi\Neos\Tests\Unit\LinkHandler\Filter\Items;

use Neos\ContentRepository\Domain\Model\NodeInterface;
use Neos\Flow\Tests\FunctionalTestCase;
use Newland\NeosTestingHelpers\InteractsWithNodes;
use Newland\Toubiz\Api\ObjectAdapter\Concern\ArticleConstants;
use Newland\Toubiz\Poi\Neos\Filter\ArticleClientFilterService;
use Newland\Toubiz\Poi\Neos\Filter\Items\ArticleRoot;
use Newland\Toubiz\Sync\Neos\Domain\Model\Article;
use Newland\Toubiz\Sync\Neos\Enum\ArticleType;
use Newland\Toubiz\Sync\Neos\Tests\Factory\ArticleFactory;

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

    public function testAppliesMainTypeFilterAutomatically(): void
    {
        [ $tour1, $tour2 ] = (new ArticleFactory($this->objectManager))->createMultiple(2, [ 'mainType' => ArticleConstants::TYPE_TOUR ]);
        [ $attr1, $attr2 ] = (new ArticleFactory($this->objectManager))->createMultiple(2, [ 'mainType' => ArticleConstants::TYPE_ATTRACTION ]);

        $filter = new ArticleRoot();
        $filter->setArticleType(ArticleConstants::TYPE_TOUR);

        $ids = array_map(
            function(Article $article) {
                return $article->getPersistenceObjectIdentifier();
            },
            $filter->getArticleQuery()->getQuery()->execute()
        );

        $this->assertContains($tour1->getPersistenceObjectIdentifier(), $ids);
        $this->assertContains($tour2->getPersistenceObjectIdentifier(), $ids);
        $this->assertNotContains($attr1->getPersistenceObjectIdentifier(), $ids);
        $this->assertNotContains($attr2->getPersistenceObjectIdentifier(), $ids);
    }

    public function testCountsArticles(): void
    {
        (new ArticleFactory($this->objectManager))->createMultiple(2, [ 'mainType' => ArticleConstants::TYPE_TOUR ]);
        (new ArticleFactory($this->objectManager))->createMultiple(2, [ 'mainType' => ArticleConstants::TYPE_ATTRACTION ]);
        $this->assertEquals(4, $this->getRoot()->countArticles());
    }

    public function testCountsArticlesWithMainTypeSet(): void
    {
        (new ArticleFactory($this->objectManager))->createMultiple(2, [ 'mainType' => ArticleConstants::TYPE_TOUR ]);
        (new ArticleFactory($this->objectManager))->createMultiple(3, [ 'mainType' => ArticleConstants::TYPE_ATTRACTION ]);

        $this->assertEquals(3, $this->getRoot(ArticleConstants::TYPE_ATTRACTION)->countArticles());
    }

    public function testAddsClientFilterBasedOnSiteNode(): void
    {
        $site = $this->initializeSite('foo-bar');
        $node = $this->initializeNode('/sites/foo-bar', null, $site);

        $filter = $this->getRoot(ArticleConstants::TYPE_TOUR, [
             'foo-bar' => [
                 'mainType' => [
                     'values' => [
                         ArticleConstants::TYPE_TOUR => 'foo-bar-client'
                     ]
                 ]
             ]
         ], $node);


        [ $currentClientTour1, $currentClientTour2 ] = (new ArticleFactory($this->objectManager))->createMultiple(2, [ 'client' => 'foo-bar-client', 'mainType' => ArticleConstants::TYPE_TOUR ]);
        [ $currentClientAttr1, $currentClientAttr2 ] = (new ArticleFactory($this->objectManager))->createMultiple(2, [ 'client' => 'foo-bar-client', 'mainType' => ArticleConstants::TYPE_ATTRACTION ]);
        [ $foreignClientTour1, $foreignClientTour2 ] = (new ArticleFactory($this->objectManager))->createMultiple(2, [ 'client' => 'another-client', 'mainType' => ArticleConstants::TYPE_TOUR ]);
        [ $foreignClientAttr1, $foreignClientAttr2 ] = (new ArticleFactory($this->objectManager))->createMultiple(2, [ 'client' => 'another-client', 'mainType' => ArticleConstants::TYPE_ATTRACTION ]);

        $ids = array_map(
            function(Article $article) {
                return $article->getPersistenceObjectIdentifier();
            },
            $filter->getArticleQuery()->getQuery()->execute()
        );

        $this->assertContains($currentClientTour1->getPersistenceObjectIdentifier(), $ids);
        $this->assertContains($currentClientTour2->getPersistenceObjectIdentifier(), $ids);
        $this->assertNotContains($currentClientAttr1->getPersistenceObjectIdentifier(), $ids);
        $this->assertNotContains($currentClientAttr2->getPersistenceObjectIdentifier(), $ids);
        $this->assertNotContains($foreignClientTour1->getPersistenceObjectIdentifier(), $ids);
        $this->assertNotContains($foreignClientTour2->getPersistenceObjectIdentifier(), $ids);
        $this->assertNotContains($foreignClientAttr1->getPersistenceObjectIdentifier(), $ids);
        $this->assertNotContains($foreignClientAttr2->getPersistenceObjectIdentifier(), $ids);
    }

    private function getRoot(int $articleType = null, array $clientFilterConfiguration = null, NodeInterface $node = null): ArticleRoot
    {
        $root = new ArticleRoot([], $node);

        if ($articleType !== null) {
            $root->setArticleType($articleType);
        }

        if ($clientFilterConfiguration !== null) {
            $clientFilterService = new ArticleClientFilterService();
            $this->inject($clientFilterService, 'configuration', $clientFilterConfiguration);
            $this->inject($root,'clientFilterService', $clientFilterService);
        }

        return $root;
    }

}
