<?php declare(strict_types=1);

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

use Newland\Toubiz\Api\ObjectAdapter\Attributes\TourAttributes;
use Newland\Toubiz\Api\ObjectAdapter\Concern\ArticleConstants;
use Newland\Toubiz\Api\Service\GeoLocation\NullService;
use Newland\Toubiz\Sync\Neos\Service\GeoLocationFactory;
use Newland\Toubiz\Sync\Neos\Tests\Factory\AddressFactory;
use Newland\Toubiz\Sync\Neos\Tests\Factory\CityDataFactory;
use Newland\Toubiz\Sync\Neos\Tests\Unit\Importer\Mock\GeoLocationFactoryMock;
use Psr\Log\NullLogger;

class TourListTest extends AbstractListTestCase
{

    public function setUp(): void
    {
        parent::setUp();
        $this->objectManager->setInstance(
            GeoLocationFactory::class,
            new GeoLocationFactoryMock(new NullService())
        );
    }

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

    protected function articleType(): int
    {
        return ArticleConstants::TYPE_TOUR;
    }

    public function testFiltersForCitiesAlongTour(): void
    {
        [ $firstCity, $secondCity ] =
            $this->articleFactory->createMultiple(2, [ 'mainType' => ArticleConstants::TYPE_CITY ]);

        $this->articleFactory->create(
            [ 'name' => '__TOUR_FIRST__', 'mainType' => $this->articleType(), 'cities' => [ $firstCity ] ]
        );
        $this->articleFactory->create(
            [ 'name' => '__TOUR_SECOND__', 'mainType' => $this->articleType(), 'cities' => [ $secondCity ] ]
        );
        $this->articleFactory->create(
            [ 'name' => '__TOUR_BOTH__', 'mainType' => $this->articleType(), 'cities' => [ $firstCity, $secondCity ] ]
        );
        $this->articleFactory->create(
            [ 'name' => '__TOUR_NONE__', 'mainType' => $this->articleType(), 'cities' => [] ]
        );

        // No filter
        $response = $this->browser->request($this->nodeUri());
        $this->assertResponseOk($response);
        $this->assertResponseContains('__TOUR_FIRST__', $response);
        $this->assertResponseContains('__TOUR_SECOND__', $response);
        $this->assertResponseContains('__TOUR_BOTH__', $response);
        $this->assertResponseContains('__TOUR_NONE__', $response);

        // Single filter
        $response =
            $this->browser->request($this->nodeUri([ 'city[0]' => $firstCity->getPersistenceObjectIdentifier() ]));
        $this->assertResponseOk($response);
        $this->assertResponseContains('__TOUR_FIRST__', $response);
        $this->assertResponseNotContains('__TOUR_SECOND__', $response);
        $this->assertResponseContains('__TOUR_BOTH__', $response);
        $this->assertResponseNotContains('__TOUR_NONE__', $response);

        // Two filters
        $response = $this->browser->request(
            $this->nodeUri(
                [
                    'city[0]' => $firstCity->getPersistenceObjectIdentifier(),
                    'city[1]' => $secondCity->getPersistenceObjectIdentifier()
                ]
            )
        );
        $this->assertResponseContains('__TOUR_FIRST__', $response);
        $this->assertResponseContains('__TOUR_SECOND__', $response);
        $this->assertResponseContains('__TOUR_BOTH__', $response);
        $this->assertResponseNotContains('__TOUR_NONE__', $response);
    }

    public function testDoesNotFilterForCityOfMainAddress(): void
    {
        $city = $this->articleFactory->create(
            [
                'mainType' => ArticleConstants::TYPE_CITY,
                'cityData' => (new CityDataFactory($this->objectManager))->make([ 'zipCodes' => [ '45678' ] ])
            ]
        );
        $this->articleFactory->create(
            [
                'mainType' => $this->articleType(),
                'name' => '__FIRST__',
                'mainAddress' => (new AddressFactory($this->objectManager))->make([ 'zip' => '45678' ])
            ]
        );
        $this->articleFactory->create(
            [
                'mainType' => $this->articleType(),
                'name' => '__SECOND__',
                'mainAddress' => (new AddressFactory($this->objectManager))->make([ 'zip' => '12345' ])
            ]
        );

        // No filter
        $response = $this->browser->request($this->nodeUri());
        $this->assertResponseOk($response);
        $this->assertResponseContains('__FIRST__', $response);
        $this->assertResponseContains('__SECOND__', $response);

        // Filter query string.
        // Nothing should be found since both created tours are not actually related to the cities
        // but only share a common zip code in their address.
        $response = $this->browser->request($this->nodeUri([ 'city[0]' => $city->getPersistenceObjectIdentifier() ]));
        $this->assertResponseOk($response);
        $this->assertResponseNotContains('__FIRST__', $response);
        $this->assertResponseNotContains('__SECOND__', $response);
    }


    public function testAddsPageSpecificOutdoorActiveApiConfiguration(): void
    {
        $config = [
            'default' => [  'apiKey' => '__DEFAULT_API_KEY__', 'client' => '__DEFAULT_CLIENT__' ],
            'sites' => [ $this->site->getNodeName() => [  'apiKey' => '__SPECIFIC_API_KEY__', 'client' => '__SPECIFIC_CLIENT__' ] ],
        ];
        $this->withMockedConfiguration(
            [ 'Newland.Toubiz.Poi.Neos.outdoorActiveConfigurations' => $config ],
            function() {
                $response = $this->browser->request($this->nodeUri());
                $this->assertResponseOk($response);
                $this->assertResponseContains('data-outdooractive-api-config.api-key="__SPECIFIC_API_KEY__"', $response);
                $this->assertResponseContains('data-outdooractive-api-config.client="__SPECIFIC_CLIENT__"', $response);
            }
        );
    }

    public function testAddsDefaultOutdoorActiveApiConfigurationIfNoSpecificExists(): void
    {
        $config = [
            'default' => [  'apiKey' => '__DEFAULT_API_KEY__', 'client' => '__DEFAULT_CLIENT__' ],
        ];
        $this->withMockedConfiguration(
            [ 'Newland.Toubiz.Poi.Neos.outdoorActiveConfigurations' => $config ],
            function() {
                $response = $this->browser->request($this->nodeUri());
                $this->assertResponseOk($response);
                $this->assertResponseContains('data-outdooractive-api-config.api-key="__DEFAULT_API_KEY__"', $response);
                $this->assertResponseContains('data-outdooractive-api-config.client="__DEFAULT_CLIENT__"', $response);
            }
        );
    }

    public function testListDoesContainNonEmptyDistances(): void
    {
        $this->articleFactory->create([ 'mainType' => 2, 'attributes' => [
            $this->attributeFactory->create([ 'name' => TourAttributes::TOUR_DURATION, 'data' => 92 ])
        ] ]);

        $response = $this->browser->request($this->nodeUri());
        $this->assertResponseOk($response);
        $this->assertResponseContains('01:32', $response);
    }

    public function testListDoesNotContainEmptyDistances(): void
    {
        $this->articleFactory->create([ 'mainType' => 2, 'attributes' => [
            $this->attributeFactory->create([ 'name' => TourAttributes::TOUR_DURATION, 'data' => 0 ])
        ] ]);

        $response = $this->browser->request($this->nodeUri());
        $this->assertResponseOk($response);
        $this->assertResponseNotContains('00:00', $response);
    }


    public function testAjaxSplitScreenListDoesContainNonEmptyDistances(): void
    {
        $this->articleFactory->create([ 'mainType' => 2, 'attributes' => [
            $this->attributeFactory->create([ 'name' => TourAttributes::TOUR_DURATION, 'data' => 92 ])
        ] ]);

        $url = sprintf(
            'http://localhost/toubiz-poi/filtered-list?node=%s&format=ajax&page=1&layout=list',
            $this->node->getContextPath()
        );

        $response = $this->browser->request($url);
        $this->assertResponseOk($response);
        $this->assertResponseContains('01:32', $response);
    }


    public function testAjaxSplitScreenListDoesNotContainEmptyDistances(): void
    {
        $this->articleFactory->create([ 'mainType' => 2, 'attributes' => [
            $this->attributeFactory->create([ 'name' => TourAttributes::TOUR_DURATION, 'data' => 0 ])
        ] ]);

        $url = sprintf(
            'http://localhost/toubiz-poi/filtered-list?node=%s&format=ajax&page=1&layout=list',
            $this->node->getContextPath()
        );

        $response = $this->browser->request($url);
        $this->assertResponseOk($response);
        $this->assertResponseNotContains('00:00', $response);
    }

}
