<?php declare(strict_types=1);

namespace Newland\Toubiz\Search\Neos\Tests\Unit\Eel\Helper;

use Neos\Flow\Tests\FunctionalTestCase;
use Newland\Contracts\Neos\Search\IndexRecordModification;
use Newland\Contracts\Neos\Search\SearchBackend;
use Newland\Contracts\Neos\Search\SearchRequest;
use Newland\Contracts\Neos\Search\SearchResult;
use Newland\Contracts\Neos\Search\SearchResultCollection;
use Newland\Toubiz\Search\Neos\Backend\SearchBackendFactory;
use Newland\Toubiz\Search\Neos\Eel\Helper\SearchResultHelper;

class SearchResultHelperTest extends FunctionalTestCase implements SearchBackend
{

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

    /** @var SearchRequest[] */
    protected $searches;

    /** @var SearchResultCollection */
    protected $searchWillReturn;

    public function setUp(): void
    {
        parent::setUp();
        $this->searches = [];
        $this->searchWillReturn = new SearchResultCollection(0);

        $this->subject = $this->objectManager->get(SearchResultHelper::class);

        $factory = $this->createMock(SearchBackendFactory::class);
        $factory->method('getSearchBackendFromConfiguration')->willReturn($this);
        $this->inject($this->subject, 'searchBackend', $factory);
    }

    public function testTransformsPropertiesToSearchRequest(): void
    {
        $this->subject->query(
            'foo',
            10,
            1,
            'de',
            '/sites/foo',
            [ 'foo' ]
        );

        $this->assertCount(1, $this->searches);
        $this->assertEquals('foo', $this->searches[0]->getSearchTerm());
        $this->assertEquals(10, $this->searches[0]->getItemsPerPage());
        $this->assertEquals(1, $this->searches[0]->getPage());
        $this->assertEquals('de', $this->searches[0]->getLanguage());
    }

    public function testUsesTypesFromConfigurationIfProvidedOnesEmpty(): void
    {
        $this->inject($this->subject, 'availableTypes', [ 'foo' => true, 'bar' => false , 'baz' => true ]);
        $this->subject->query(
            'foo',
            10,
            1,
            'de',
            '/sites/foo',
            [ ]
        );

        $this->assertCount(1, $this->searches);
        $this->assertContains('foo', $this->searches[0]->getTypes());
        $this->assertNotContains('bar', $this->searches[0]->getTypes());
        $this->assertContains('baz', $this->searches[0]->getTypes());
    }

    public function testTransformsPageScopeFromConfigurationToCorrectPageNodeName(): void
    {
        $this->inject($this->subject, 'availableTypes', [ 'page' => true ]);
        $this->subject->query(
            'foo',
            10,
            1,
            'de',
            '/sites/foo',
            [ ]
        );

        $this->assertCount(1, $this->searches);
        $this->assertContains('/sites/foo', $this->searches[0]->getScopes());
    }

    public function testTransformsPassedPageScopeToCorrectPageNodeName(): void
    {
        $this->subject->query(
            'foo',
            10,
            1,
            'de',
            '/sites/foo',
            [ 'page' ]
        );

        $this->assertCount(1, $this->searches);
        $this->assertContains('/sites/foo', $this->searches[0]->getScopes());
    }

    public function initialize(): void
    {
        // SearchBackend mock
    }

    public function setSource(string $source): void
    {
        // SearchBackend mock
    }

    public function createOrUpdateIndexEntry(IndexRecordModification $modification): void
    {
        // SearchBackend mock
    }

    public function afterIndexing(): void
    {
        // SearchBackend mock
    }

    public function deleteObsoleteIndexEntries(array $identifiersToRetain): void
    {
        // SearchBackend mock
    }

    public function search(SearchRequest $request): SearchResultCollection
    {
        $this->searches[] = $request;
        return $this->searchWillReturn;
    }
}
