<?php declare(strict_types=1);

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

use Neos\Flow\Mvc\View\ViewInterface;
use Newland\Toubiz\Api\ObjectAdapter\Concern\ArticleConstants;
use Newland\Toubiz\Poi\Neos\Controller\FilteredListsController;
use Newland\Toubiz\Poi\Neos\Tests\Unit\ViewHelpers\Widget\Controller\Mock\MockView;
use Newland\Toubiz\Sync\Neos\Domain\Model\Article;
use Newland\Toubiz\Sync\Neos\Domain\Repository\ArticleRepository;
use Newland\Toubiz\Sync\Neos\Tests\Factory\AttributeFactory;
use Newland\Toubiz\Sync\Neos\Tests\Factory\CategoryFactory;

class FilteredListsControllerTest extends ControllerBaseTest
{
    /** @var FilteredListsController */
    protected $subject;

    /** @var AttributeFactory */
    protected $attributeFactory;

    protected $subjectClass = FilteredListsController::class;

    public function setUp(): void
    {
        parent::setUp();

        $this->attributeFactory = new AttributeFactory($this->objectManager);
    }

    public function testAssignsAllToursForConfiguredMainTypeToView(): void
    {
        $germanMatching = $this->articleFactory->create([ 'language' => 'de', 'mainType' => 2 ]);
        $germanNonMatching = $this->articleFactory->create([ 'language' => 'de', 'mainType' => 1 ]);
        $englishMatching = $this->articleFactory->create([ 'language' => 'en', 'mainType' => 2 ]);
        $this->callAction('show', [], [ 'articleType' => 2 ]);

        $ids = array_map(
            function(Article $article) {
                return $article->getPersistenceObjectIdentifier();
            },
            $this->view->assignments['articles']
        );

        $this->assertContains($germanMatching->getPersistenceObjectIdentifier(), $ids, 'Should contain german article with matching type');
        $this->assertNotContains($germanNonMatching->getPersistenceObjectIdentifier(), $ids, 'Should not contain german article with other type');
        $this->assertNotContains($englishMatching->getPersistenceObjectIdentifier(), $ids, 'Should not contain english article with matching type');
    }

    public function testShouldFilterForPreselectedCategories(): void
    {
        $categoryFactory = new CategoryFactory($this->objectManager);
        $germanCategory = $categoryFactory->create([ 'language' => 'de' ]);
        $germanOtherCategory = $categoryFactory->create([ 'language' => 'de' ]);
        $englishCategory = $categoryFactory->create([ 'language' => 'en' ]);

        $germanMatching = $this->articleFactory->create([ 'language' => 'de', 'mainType' => 2, 'categories' => [ $germanCategory ] ]);
        $englishMatching = $this->articleFactory->create([ 'language' => 'en', 'mainType' => 2, 'categories' => [ $germanOtherCategory ] ]);
        $germanNonMatching = $this->articleFactory->create([ 'language' => 'de', 'mainType' => 2, 'categories' => [ $englishCategory ] ]);

        $this->callAction('show', [], [ 'articleType' => 2, 'preselectedCategories' => [ $germanCategory->getPersistenceObjectIdentifier() ] ]);
        $ids = array_map(
            function(Article $article) {
                return $article->getPersistenceObjectIdentifier();
            },
            $this->view->assignments['articles']
        );

        $this->assertContains($germanMatching->getPersistenceObjectIdentifier(), $ids, 'Should contain german article with matching type');
        $this->assertNotContains($germanNonMatching->getPersistenceObjectIdentifier(), $ids, 'Should not contain german article with other type');
        $this->assertNotContains($englishMatching->getPersistenceObjectIdentifier(), $ids, 'Should not contain english article with matching type');

    }

    public function testShouldFilterForPreselectedProperties(): void
    {
        $germanMatching = $this->articleFactory->create([
             'language' => 'de',
             'mainType' => 2,
             'attributes' => [ $this->attributeFactory->make([ 'name' => 'properties', 'data' => 'loopTour' ]) ],
         ]);
        $englishMatching = $this->articleFactory->create([
            'language' => 'en',
            'mainType' => 2,
            'attributes' => [ $this->attributeFactory->make([ 'name' => 'properties', 'data' => 'loopTour' ]) ],
        ]);
        $germanNonMatching = $this->articleFactory->create([
            'language' => 'de',
            'mainType' => 2,
            'attributes' => [ $this->attributeFactory->make([ 'name' => 'properties', 'data' => 'oneWayTour' ]) ],
        ]);

        $this->callAction('show', [], [ 'articleType' => 2, 'preselectedProperties' => [ 'properties:loopTour' ] ]);
        $ids = array_map(
            function(Article $article) {
                return $article->getPersistenceObjectIdentifier();
            },
            $this->view->assignments['articles']
        );

        $this->assertContains($germanMatching->getPersistenceObjectIdentifier(), $ids, 'Should contain german article with matching type');
        $this->assertNotContains($germanNonMatching->getPersistenceObjectIdentifier(), $ids, 'Should not contain german article with other type');
        $this->assertNotContains($englishMatching->getPersistenceObjectIdentifier(), $ids, 'Should not contain english article with matching type');
    }


    public function testShouldFilterForPreselectedTags(): void
    {
        $germanMatching = $this->articleFactory->create([
             'language' => 'de',
             'mainType' => ArticleConstants::TYPE_ATTRACTION,
             'attributes' => [ $this->attributeFactory->make([ 'name' => 'tag', 'data' => 'foo' ]) ],
         ]);
        $englishMatching = $this->articleFactory->create([
            'language' => 'en',
            'mainType' => ArticleConstants::TYPE_ATTRACTION,
            'attributes' => [ $this->attributeFactory->make([ 'name' => 'tag', 'data' => 'foo' ]) ],
        ]);
        $germanNonMatching = $this->articleFactory->create([
            'language' => 'de',
            'mainType' => ArticleConstants::TYPE_ATTRACTION,
            'attributes' => [ $this->attributeFactory->make([ 'name' => 'tag', 'data' => 'bar' ]) ],
        ]);

        $this->callAction('show', [], [ 'articleType' => ArticleConstants::TYPE_ATTRACTION, 'preselectedTags' => [ 'tag:foo' ] ]);
        $ids = array_map(
            function(Article $article) {
                return $article->getPersistenceObjectIdentifier();
            },
            $this->view->assignments['articles']
        );

        $this->assertContains($germanMatching->getPersistenceObjectIdentifier(), $ids, 'Should contain german article with matching type');
        $this->assertNotContains($germanNonMatching->getPersistenceObjectIdentifier(), $ids, 'Should not contain german article with other type');
        $this->assertNotContains($englishMatching->getPersistenceObjectIdentifier(), $ids, 'Should not contain english article with matching type');
    }

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

        // Taint repository on purpose
        $this->objectManager->get(ArticleRepository::class)->setLanguage(null);

        $this->callAction('show', [], [ 'articleType' => 2 ]);

        $ids = array_map(
            function(Article $article) {
                return $article->getPersistenceObjectIdentifier();
            },
            $this->view->assignments['articles']
        );

        $this->assertContains($german->getPersistenceObjectIdentifier(), $ids, 'Should contain german article');
        $this->assertNotContains($english->getPersistenceObjectIdentifier(), $ids, 'Should not contain english article');
    }

    public function getView(): ViewInterface
    {
        $this->view = new MockView();

        return $this->view;
    }
}
