<?php
namespace Newland\Toubiz\Poi\Neos\Tests\Routing;

use Neos\Flow\Mvc\Routing\Dto\ResolveResult;
use Neos\Flow\Tests\FunctionalTestCase;
use Newland\PageFrameProvider\Definition\RoutingConfigurationHelper;
use Newland\PageFrameProvider\Service\PageFrameLinkingService;
use Newland\Toubiz\Poi\Neos\Routing\ArticleDetailRoutePart;
use Newland\Toubiz\Poi\Neos\Routing\ArticleRoutingService;
use Newland\PageFrameProvider\Service\PageFrameContextService;

class ArticleDetailRoutePartTest extends FunctionalTestCase
{
    /** @var ArticleDetailRoutePart */
    private $subject;

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

        $pageFrameContext = new PageFrameContextService();
        $pageFrameContext->setDimensions([ 'language' => [ 'de' ] ]);

        $this->subject = new ArticleDetailRoutePart();
        $this->inject($this->subject, 'pageFrameContext', $pageFrameContext);
        $this->inject($this->subject, 'pageFrameLinkingService', new PageFrameLinkingService());
        $this->inject($this->subject, 'configurationHelper', new RoutingConfigurationHelper());
        $this->inject($this->subject, 'typeConfiguration', [
            '_fallback' => 'poi/detail/fallback',
            '42' => 'poi/detail/for-42',
            '24' => '/has/leading/and/trailing/slashes/',
        ]);
    }

    public function testRoutesStartingWithTheGivenPrefixesMatch()
    {
        $url = 'poi/detail/fallback/my-detail-url';
        $this->assertTrue($this->subject->match($url), 'URL ' . $url . ' should match');

        $url = 'poi/detail/for-42/my-detail-url';
        $this->assertTrue($this->subject->match($url), 'URL ' . $url . ' should match');
    }

    public function testRoutesWithGivenPrefixesNotAtStartDontMatch()
    {
        $url = 'foo/bar/poi/detail/fallback/my-detail-url';
        $this->assertFalse($this->subject->match($url), 'URL ' . $url . ' should match');

        $url = 'some/other/path/poi/detail/for-42/my-detail-url';
        $this->assertFalse($this->subject->match($url), 'URL ' . $url . ' should match');
    }

    public function testStripsPrefixFromMatchingUrl()
    {
        $url = 'poi/detail/fallback/my-detail-url';
        $this->assertTrue($this->subject->match($url), 'URL ' . $url . ' should match');
        $this->assertEquals('/my-detail-url', $url);
    }

    public function testDoesNotStripAnythingFromUrlIfNotMatching()
    {
        $url = 'non/matching/url';
        $this->assertFalse($this->subject->match($url), 'URL ' . $url . ' should not match');
        $this->assertEquals('non/matching/url', $url);
    }

    public function testAlsoMatchesIfDefinedWithLeadingAndTrailingSlashes()
    {
        $url = 'has/leading/and/trailing/slashes/my-detail-url';
        $this->assertTrue($this->subject->match($url), 'URL ' . $url . ' should match');
    }

    public function testDoesNotRemoveSlashFromUrlIfDeclaredWithSurroundingSlashes()
    {
        $url = 'has/leading/and/trailing/slashes/my-detail-url';
        $this->assertTrue($this->subject->match($url), 'URL ' . $url . ' should match');
        $this->assertEquals('/my-detail-url', $url);
    }

    public function testDoesNotResolveUrlIfNotPointingToPageFrame()
    {
        $routeValues = $this->routeValues(
            [
                '@package' => 'foo.bar',
                '@controller' => 'foo',
                '@action' => 'bar',
            ]
        );
        $this->assertFalse($this->subject->resolve($routeValues));
    }

    public function testDoesNotResolveUrlIfTypeArgumentNotSpecified()
    {
        $routeValues = $this->routeValues();
        $this->assertFalse($this->subject->resolve($routeValues));
    }

    public function testResolvesUrlWithCorrectUrlFragmentForType()
    {
        $routeValues = $this->routeValues([ '--plugin' => [ '_type' => '42' ] ]);
        $result = $this->subject->resolve($routeValues);

        $this->assertNotFalse($result);
        $this->assertInstanceOf(ResolveResult::class, $result);
        $this->assertEquals('poi/detail/for-42', $result->getResolvedValue());
    }

    public function testWillRemoveTypeFromRouteValuesIfResolves()
    {
        $routeValues = $this->routeValues([ '--plugin' => [ '_type' => '42' ] ]);

        $this->assertNotFalse($this->subject->resolve($routeValues));
        $this->assertNull($routeValues['--plugin']['_type'] ?? null);
    }

    public function testResolvesUrlWithFallbackUrlFragmentIfTypeNotConfigured()
    {
        $routeValues = $this->routeValues([ '--plugin' => [ '_type' => '999' ] ]);
        $result = $this->subject->resolve($routeValues);

        $this->assertNotFalse($result);
        $this->assertInstanceOf(ResolveResult::class, $result);
        $this->assertEquals('poi/detail/fallback', $result->getResolvedValue());
    }

    /**
     * Returns a route values array that is valid for the detail view if you add `--plugin._type`.
     *
     * @param array $overrides
     * @return array
     */
    private function routeValues(array $overrides = []): array
    {
        return array_replace_recursive(
            [
                '@package' => 'newland.pageframeprovider',
                '@controller' => 'pageframe',
                '@action' => 'show',
                '--plugin' => [
                    '@package' => 'newland.toubiz.poi.neos',
                    '@controller' => 'pointofinterests',
                    '@action' => 'show',
                ],
            ],
            $overrides
        );
    }
}
