<?php declare(strict_types=1);

namespace Newland\Toubiz\Sync\Neos\Tests\Unit\Translation;

use Neos\ContentRepository\Domain\Model\NodeInterface;
use Neos\Flow\Http\Uri;
use Neos\Flow\Mvc\ResponseInterface;
use Neos\Flow\Mvc\Routing\UriBuilder;
use Neos\Flow\Security\Authorization\TestingPrivilegeManager;
use Neos\Flow\Security\SessionDataContainer;
use Neos\Flow\Tests\FunctionalTestCase;
use Neos\Neos\Service\LinkingService;
use Newland\NeosCommon\Service\ControllerContextFactory;
use Newland\NeosRoutingBehaviourHooks\Foundation\RouteWrappingHelper;
use Newland\NeosTestingHelpers\BrowserResponseAssertions;
use Newland\NeosTestingHelpers\InteractsWithNodes;
use Newland\Toubiz\Poi\Neos\DataSource\PointOfInterestDataSource;
use Newland\Toubiz\Sync\Neos\Translation\CurrentLanguageService;

class CurrentLanguageServiceTest extends FunctionalTestCase
{
    use InteractsWithNodes, BrowserResponseAssertions;
    protected static $testablePersistenceEnabled = true;
    protected $testableSecurityEnabled = true;

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

    public function setUp(): void
    {
        parent::setUp();
        $this->subject = $this->objectManager->get(CurrentLanguageService::class);
        $this->subject->reset();
    }

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

        // Forgetting route wrapping helper as it holds on to old state.
        $this->objectManager->forgetInstance(RouteWrappingHelper::class);
        parent::tearDown();
    }

    public function testCallsGivenBlockOnceInitially(): void
    {
        $called = false;
        $this->subject->onInitialLanguageAvailable(function() use (&$called) {
            $called = true;
        });
        $this->assertTrue($called);
    }

    public function testUsesLanguageDimensionOfFrontendNode(): void
    {
        $lang = null;
        $this->subject->onInitialLanguageAvailable(function($l) use (&$lang) { $lang = $l; });
        $this->assertNotEquals('fr', $lang);

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

        $this->assertEquals('fr', $lang);
    }

    public function testUsesLanguageDimensionOfDataSourceReference(): void
    {
        $lang = null;
        $this->subject->onInitialLanguageAvailable(function($l) use (&$lang) { $lang = $l; });
        $this->assertNotEquals('fr', $lang);

        $uri = $this->dataSourceUri($this->node('fr'), PointOfInterestDataSource::getIdentifier());
        $response = $this->browser->request($uri);
        $this->assertResponseOk($response);

        $this->assertEquals('fr', $lang);
    }


    private function node(string $language): NodeInterface
    {
        $nodeName = uniqid('site', false);
        $site = $this->initializeSite($nodeName);

        $node = $this->initializeNode(sprintf('/sites/%s', $nodeName), 'live', $site, [], $language);
        $node->setProperty('uriPathSegment', uniqid('document-node', false));
        $this->persistNode($node);

        $this->initializeNode(
            sprintf('/sites/%s/main', $nodeName),
            'live',
            $site,
            [],
            $language,
            'Neos.Neos:ContentCollection'
        );
        return $node;
    }

    protected function nodeUri(NodeInterface $node, array $arguments = [ ]): Uri
    {
        $uri = $this->objectManager->get(LinkingService::class)->createNodeUri(
            $this->objectManager->get(ControllerContextFactory::class)->initializeFakeControllerContext($node),
            $node,
            null,
            'html',
            false,
            $arguments
        );
        return new Uri($uri);
    }

    private function dataSourceUri(NodeInterface $node, string $dataSource): Uri
    {
        /** @var TestingPrivilegeManager $manager */
        $manager = $this->privilegeManager;
        $manager->setOverrideDecision(true);
        return new Uri(sprintf(
            'http://toubiz-frontend.ddev.site/neos/service/data-source/%s?node=%s',
            $dataSource,
            urlencode($node->getContextPath())
        ));
    }
}
