<?php

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

use Neos\ContentRepository\Domain\Model\Node;
use Neos\Flow\Http\Request;
use Neos\Flow\Http\Uri;
use Neos\Flow\Mvc\ActionRequest;
use Neos\Flow\Http\Response;
use Neos\Flow\Tests\FunctionalTestCase;
use Neos\FluidAdaptor\Core\Widget\WidgetContext;
use Neos\Neos\Domain\Model\Site;
use Neos\Neos\Service\LinkingService;
use Newland\NeosCommon\Service\NodeService;
use Newland\NeosTestingHelpers\InteractsWithNodes;
use Newland\Toubiz\Api\ObjectAdapter\Concern\ArticleConstants;
use Newland\Toubiz\Poi\Neos\Service\LinkListService;
use Newland\Toubiz\Poi\Neos\Tests\Factory\AddressFactory;
use Newland\Toubiz\Poi\Neos\Tests\Unit\ViewHelpers\Widget\Controller\Mock\MockView;
use Newland\Toubiz\Poi\Neos\ViewHelpers\Widget\Controller\LinkListController;
use Newland\Toubiz\Sync\Neos\Domain\Model\Article;
use Newland\Toubiz\Sync\Neos\Domain\Model\CityData;
use Newland\Toubiz\Sync\Neos\Tests\Factory\ArticleFactory;
use Newland\Toubiz\Sync\Neos\Tests\Factory\CityDataFactory;

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

    /** @var LinkListController */
    private $subject;

    /** @var MockView */
    private $view;

    /** @var Article */
    private $article;

    /** @var Node */
    private $node;

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

        $this->node = $this->initializeNode('/sites/foo-bar', null, new Site('foo-bar'), [], 'en');
        $this->article = (new ArticleFactory($this->objectManager))->make();
        $this->view = new MockView();
        $this->subject = $this->objectManager->get(LinkListController::class);
        $this->inject($this->subject, 'view', $this->view);
    }

    public function testShouldNotGenerateLinksIfDisabled(): void
    {

        $this->callIndexAction(
            [
                'sites' => [
                    'default' => [
                        'enabled' => false,
                        'data' => [
                            'foo' => [ 'target' => 'foo' ],
                        ],
                    ],
                ],
            ]
        );

        $this->assertCount(0, $this->view->assignments['links']);
    }

    public function testFillsPlaceholdersInUris(): void
    {
        $city = new CityData();
        $city->setIdTomas('id_tomas');
        $city->setIdToubiz('id_toubiz');
        $this->article->setCityData($city);

        $this->callIndexAction(
            [
                'sites' => [
                    'default' => [
                        'enabled' => true,
                        'data' => [
                            'foo' => [ 'target' => 'foo/{idToubiz}/bar/{idTomas}/baz/{unknown}' ],
                        ],
                    ],
                ],

            ]
        );

        $this->assertCount(1, $this->view->assignments['links']);
        $this->assertEquals(
            'foo/id_toubiz/bar/id_tomas/baz/{unknown}',
            $this->view->assignments['links']['foo']['url']
        );
    }

    public function testUsesLinkingServiceToResolveNodeUris(): void
    {
        $linkingService = $this->createMock(LinkingService::class);
        $linkingService->method('convertUriToObject')->willReturn($this->node);
        $linkingService
            ->expects($this->once())
            ->method('createNodeUri')
            ->with(
                $this->anything(),
                $this->equalTo($this->node),
                $this->equalTo($this->node),
                null,
                false,
                [
                    'super' => [
                        'cool' => [
                            'city' => [
                                'query' => [
                                    $this->article->getPersistenceObjectIdentifier(),
                                ],
                            ],
                        ],
                    ],
                ]
            )->willReturn('generated/uri');

        $this->inject($this->subject, 'linkingService', $linkingService);
        $this->callIndexAction(
            [
                'sites' => [
                    'default' => [
                        'enabled' => true,
                        'data' => [
                            'foo' => [
                                'target' => 'node://' . $this->node->getIdentifier(),
                                'queryParameters' => [
                                    'city' => 'super.cool.city.query',
                                ],
                            ],
                        ],
                    ],
                ],
            ]
        );

        $this->assertEquals('generated/uri', $this->view->assignments['links']['foo']['url']);
    }

    public function testHideLinkForEmptyResult(): void
    {
        $cityData = (new CityDataFactory($this->objectManager))->make([ 'zipCodes' => [ 10245 ] ]);
        $articleFactory = new ArticleFactory($this->objectManager);
        $this->article = $articleFactory->make(
            [
                'mainType' => ArticleConstants::TYPE_CITY
                ,
                'cityData' => $cityData,
            ]
        );

        // attraction outside region
        $articleFactory->create(
            [
                'mainType' => 0,
                'language' => 'en',
                'mainAddress' => AddressFactory::make(null, [ 'zip' => '99999' ]),
            ]
        );

        // tour within region
        $articleFactory->create(
            [
                'mainType' => 2,
                'language' => 'en',
                'mainAddress' => AddressFactory::make(null, [ 'zip' => '10245' ]),
            ]
        );

        $this->callIndexAction(
            [
                'sites' => [
                    'default' => [
                        'enabled' => true,
                        'data' => [
                            'attraction' => [
                                'target' => 'node://' . $this->node->getIdentifier(),
                                'pluginNamespace' => '--some-plugin-namespace',
                                'type' => 'article',
                                'mainType' => 0,
                            ],
                            'tours' => [
                                'target' => 'node://' . $this->node->getIdentifier(),
                                'pluginNamespace' => '--some-plugin-namespace',
                                'type' => 'article',
                                'mainType' => 2,
                            ],
                        ],
                    ],
                ],
            ]
        );

        $this->assertFalse(
            $this->view->assignments['links']['attraction']['hasResults'],
            'The attraction is outside the region and should not be found.'
        );
        $this->assertTrue(
            $this->view->assignments['links']['tours']['hasResults'],
            'The tour is within the region and should be found.'
        );
    }

    private function callIndexAction(array $linksConfiguration): Response
    {
        $request = new ActionRequest(Request::create(new Uri('http://localhost')));

        $context = new WidgetContext();
        $context->setNonAjaxWidgetConfiguration(
            [
                'article' => $this->article,
                'node' => $this->node,
            ]
        );
        $request->setArgument('__widgetContext', $context);
        $request->setControllerActionName('index');

        $response = new Response();

        $linkListService = new LinkListService();
        $this->inject($linkListService, 'linksConfiguration', $linksConfiguration);

        $this->inject($this->subject, 'linkListService', $linkListService);

        $this->inject($this->subject, 'nodeService', new NodeService());
        $this->subject->processRequest($request, $response);
        return $response;
    }

}
