<?php declare(strict_types=1);

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

use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
use Neos\ContentRepository\Domain\Model\NodeInterface;
use Neos\ContentRepository\Domain\Service\Context;
use Neos\ContentRepository\Domain\Service\NodeTypeManager;
use Neos\Flow\Http\Response;
use Neos\Flow\Http\Uri;
use Neos\Flow\Mvc\RequestInterface;
use Neos\Flow\Mvc\Routing\Router;
use Neos\Flow\Tests\FunctionalTestCase;
use Neos\Neos\Domain\Model\Site;
use Neos\Neos\Domain\Repository\SiteRepository;
use Neos\Neos\Service\LinkingService;
use Newland\NeosCommon\Service\ControllerContextFactory;
use Newland\NeosTestingHelpers\InteractsWithNodes;
use Newland\Toubiz\Poi\Neos\Service\ArticleUrlService;
use Newland\Toubiz\Sync\Neos\Tests\Factory\ArticleFactory;
use Psr\Http\Message\ResponseInterface;

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

    /** @var Site */
    protected $site;

    /** @var NodeInterface */
    protected $documentNode;

    /** @var NodeInterface */
    protected $contentCollection;

    /** @var NodeInterface */
    protected $node;

    /** @var NodeTypeManager */
    protected $nodeTypeManager;

    /** @var ArticleFactory */
    protected $articleFactory;

    /** @var Uri */
    protected $nodeUri;

    /** @var ArticleUrlService */
    protected $articleUrlService;

    public function setUp(): void
    {
        parent::setUp();
        $this->nodeTypeManager = $this->objectManager->get(NodeTypeManager::class);
        $this->articleUrlService = $this->objectManager->get(ArticleUrlService::class);
        $this->articleFactory = new ArticleFactory($this->objectManager);

        // Site and site node
        $nodeName = uniqid('site', false);
        $this->site = $this->initializeSite($nodeName);
        $this->initializeNode(sprintf('/sites/%s', $nodeName), 'live', $this->site);

        // Document node
        $uriSegment = uniqid('document-node', false);
        $this->documentNode = $this->initializeNode(sprintf('/sites/%s/bar-baz', $nodeName), 'live', $this->site);
        $this->documentNode->setProperty('uriPathSegment', $uriSegment);
        $this->persistNode($this->documentNode);

        // Content Collection and node that is tested.
        $this->contentCollection = $this->initializeNode(sprintf('/sites/%s/bar-baz/main', $nodeName), 'live', $this->site, [], null, 'Neos.Neos:ContentCollection');
        $this->node = $this->initializeNode(sprintf('/sites/%s/bar-baz/main/test-abc', $nodeName), 'live', $this->site);

        $uri = $this->objectManager->get(LinkingService::class)->createNodeUri(
            $this->objectManager->get(ControllerContextFactory::class)->initializeFakeControllerContext($this->documentNode),
            $this->documentNode
        );
        $this->nodeUri = new Uri($uri);
    }
    protected function assertResponseOk(ResponseInterface $response): void
    {
        $this->assertResponseNotContains('Uncaught Exception in Flow.*', $response, (string) $response->getBody());
        $this->assertEquals(200, $response->getStatusCode());
        $this->assertResponseNotContains('<!-- Exception while rendering(.|\\n)*?-->', $response);
    }

    protected function assertResponseContains(
        string $stringToContain,
        ResponseInterface $response,
        string $message = null
    ): void {
        preg_match('/' . $stringToContain . '/', (string) $response->getBody(), $matches);
        $this->assertNotEmpty($matches, $message ?? sprintf('Response should contain "%s"', $stringToContain));
    }

    protected function assertResponseNotContains(
        string $stringToNotContain,
        ResponseInterface $response,
        string $message = null
    ): void {


        preg_match('/' . $stringToNotContain . '/', (string) $response->getBody(), $matches);
        $message = sprintf(
            "Response should not contain '%s' but contains [%s]\n%s",
            $stringToNotContain,
            json_encode($matches),
            $message
        );

        $this->assertEmpty($matches, $message);
    }

}
