<?php declare(strict_types=1);

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

use Neos\Flow\Tests\FunctionalTestCase;
use Newland\Toubiz\Sync\Neos\Domain\Repository\ArticleRepository;

// TranslatableRepository is tested based on ArticleRepository
class TranslatableRepositoryTest extends FunctionalTestCase
{

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

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

    /**
     * @dataProvider validLanguagesDataProvider
     * @param string $language
     */
    public function testAddsLanguageWhereClauseByDefault(string $language): void
    {
        $this->subject->setLanguage($language);
        $dql = $this->subject->createQueryBuilder('article')->getDQL();
        $this->assertContains(
            sprintf("language = '%s'", $language),
            $dql
        );
    }

    public function testDoesNotAddWhereClauseIfLanguageSetToNull(): void
    {
        $this->subject->setLanguage(null);
        $dql = $this->subject->createQueryBuilder('article')->getDQL();
        $this->assertNotContains('language =', $dql);
    }

    /**
     * @dataProvider validLanguagesDataProvider
     * @param string $language
     */
    public function testAddsAdditionalWhereClauseIfLaxLanguageHandlingEnabled(string $language): void
    {
        $this->subject->setStrictLanguageHandling(false);
        $this->subject->setLanguage($language);
        $dql = $this->subject->createQueryBuilder('article')->getDQL();
        $this->assertContains('language IS NULL', $dql);

        $this->subject->setStrictLanguageHandling(true);
        $this->subject->setLanguage($language);
        $dql = $this->subject->createQueryBuilder('article')->getDQL();
        $this->assertNotContains('language IS NULL', $dql);
    }

    /**
     * @dataProvider validLanguagesDataProvider
     * @param string $language
     */
    public function testAllowsTemporarilyDisablingLanguageHandlingForSingleClosure(string $language): void
    {
        $this->subject->setLanguage($language);
        $queryBefore = $this->subject->createQueryBuilder('article');
        $this->assertContains(
            sprintf("language = '%s'", $language),
            $queryBefore->getDQL()
        );

        $queryWithout = $this->subject->withoutLanguageHandling(function() {
             return $this->subject->createQueryBuilder('article');
        });
        $this->assertNotContains(
            sprintf("language = '%s'", $language),
            $queryWithout->getDQL()
        );

        $queryAfter = $this->subject->createQueryBuilder('article');
        $this->assertContains(
            sprintf("language = '%s'", $language),
            $queryAfter->getDQL()
        );
    }

    /**
     * @dataProvider validLanguagesDataProvider
     * @param string $language
     */
    public function testAllowsTemporarilySettingAnotherLanguage(string $language): void
    {
        $originalLang = $language === 'de' ? 'en' : 'de';
        $this->subject->setLanguage($originalLang);

        $queryBefore = $this->subject->createQueryBuilder('article');
        $this->assertContains(
            sprintf("language = '%s'", $originalLang),
            $queryBefore->getDQL()
        );

        $queryWith = $this->subject->withLanguage($language, function() {
            return $this->subject->createQueryBuilder('article');
        });
        $this->assertNotContains(
            sprintf("language = '%s'", $originalLang),
            $queryWith->getDQL()
        );

        $queryAfter = $this->subject->createQueryBuilder('article');
        $this->assertContains(
            sprintf("language = '%s'", $originalLang),
            $queryAfter->getDQL()
        );
    }

    public function testTemporarilySettingLanguageToNullDoesNotDisableLanguageHandling(): void
    {
        $this->subject->setLanguage('de');

        $queryBefore = $this->subject->createQueryBuilder('article');
        $this->assertContains("language = 'de'", $queryBefore->getDQL());

        $queryWith = $this->subject->withLanguage(null, function() {
            return $this->subject->createQueryBuilder('article');
        });
        $this->assertContains("language = 'de'", $queryWith->getDQL());
    }

    /**
     * @dataProvider validLanguagesDataProvider
     * @param string $language
     */
    public function testAddsWhereClauseOnTopOfOtherClauses(string $language): void
    {
        $this->subject->setLanguage($language);

        $query = $this->subject->createQueryBuilder('article');
        $query->where($query->expr()->eq('foo', 'bar'));
        $dql = $query->getDQL();

        $this->assertContains(
            sprintf("language = '%s'", $language),
            $dql
        );
    }


    public function validLanguagesDataProvider(): array
    {
        return [
            [ 'de' ],
            [ 'en' ],
            [ 'fr' ],
            [ 'es' ],
        ];
    }
}
