<?php declare(strict_types=1);

namespace Newland\Toubiz\Poi\Neos\Tests\Integration\FilteredTeaserList;

use Newland\Toubiz\Api\ObjectAdapter\Concern\ArticleConstants;
use Newland\Toubiz\Poi\Neos\Service\LinkListService;
use Newland\Toubiz\Poi\Neos\Tests\Integration\IntegrationTestCase;

abstract class FilteredTeaserListTestCase extends IntegrationTestCase
{
    protected abstract function articleType(): int;

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

        $this->node->setNodeType($this->nodeTypeManager->getNodeType('Newland.Toubiz.Poi.Neos:FilteredTeaserList'));
        $this->node->setProperty('articleType', $this->articleType());
        $this->persistNode($this->node);

        $service = $this->createMock(LinkListService::class);
        $service->method('getLinkTargetNodeByClientAndArticleType')->willReturn('');
        $this->objectManager->setInstance(LinkListService::class, $service);
    }

    public function tearDown(): void
    {
        $this->objectManager->forgetInstance(LinkListService::class);
        parent::tearDown();
    }

    public function testRendersArticles(): void
    {
        $this->articleFactory->create([ 'mainType' => $this->articleType(), 'name' => '__FIRST__' ]);
        $this->articleFactory->create([ 'mainType' => $this->articleType(), 'name' => '__SECOND__' ]);

        $response = $this->browser->request($this->nodeUri);
        $this->assertResponseOk($response);

        $this->assertResponseContains('__FIRST__', $response);
        $this->assertResponseContains('__SECOND__', $response);
    }

    /** @dataProvider provideOtherArticleTypes */
    public function testDoesNotShowArticlesOfDifferentType($type): void
    {
        $hash = md5(random_bytes(32));
        $correctName = sprintf('__CORRECT_%s__', $hash);
        $otherName = sprintf('__OTHER_TYPE_%s__', $hash);
        $this->articleFactory->create([ 'mainType' => $this->articleType(), 'name' => $correctName ]);
        $this->articleFactory->create([ 'mainType' => (int) $type, 'name' => $otherName ]);

        $response = $this->browser->request($this->nodeUri);
        $this->assertResponseOk($response);

        $this->assertResponseContains($correctName, $response);
        $this->assertResponseNotContains($otherName, $response);
    }

    public function testDoesNotContainHiddenArticles(): void
    {
        $visible = $this->articleFactory->create([ 'mainType' => $this->articleType(), 'hidden' => false, 'name' => 'visible_' . md5(random_bytes(32)) ]);
        $hidden = $this->articleFactory->create([ 'mainType' => $this->articleType(), 'hidden' => true, 'name' => 'hidden_' . md5(random_bytes(32)) ]);

        $response = $this->browser->request($this->nodeUri());
        $this->assertResponseOk($response);

        $this->assertResponseContains($visible->getName(), $response);
        $this->assertResponseNotContains($hidden->getName(), $response);
    }

    public function provideOtherArticleTypes(): array
    {
        $otherTypes = array_filter(
            ArticleConstants::ALL_TYPES,
            function ($type) {
                return $type !== $this->articleType();
            }
        );

        return array_map(
            function ($type) {
                return [ $type ];
            },
            $otherTypes
        );
    }


    public function testRendersSlots(): void
    {
        $this->articleFactory->createMultiple(1, [ 'mainType' => $this->articleType() ]);
        $response = $this->browser->request($this->nodeUri());
        $this->assertResponseOk($response);

        foreach ($this->provideSlotsThatShouldExist() as [ $slot ]) {
            $this->assertResponseContains(sprintf('Slot(%s)', $slot), $response, null, false);
        }
    }

    public function provideSlotsThatShouldExist(): array
    {
        return [
            [ 'aboveAll' ],
            [ 'belowAll' ],
            [ 'aboveTeaser' ],
            [ 'belowTeaser' ],
            [ 'aboveTitle' ],
            [ 'belowTitle' ],
            [ 'aboveTeaserTitle' ],
            [ 'belowTeaserTitle' ],
            [ 'aboveImage' ],
            [ 'belowImage' ],
            [ 'aboveTeaserImage' ],
            [ 'belowTeaserImage' ],
        ];
    }
}
