<?php


namespace Opentalent\OtCore\Tests\Unit\Website;


use Nimut\TestingFramework\TestCase\UnitTestCase;
use Opentalent\OtCore\Exception\InvalidWebsiteConfigurationException;
use Opentalent\OtCore\Exception\NoSuchWebsiteException;
use Opentalent\OtCore\Tests\Unit\Fixtures\PageFixtures;
use Opentalent\OtCore\Tests\Unit\Fixtures\WebsiteFixtures;
use Opentalent\OtCore\Tests\Unit\QueryBuilderProphet;
use Opentalent\OtCore\Website\OtPageRepository;
use Opentalent\OtCore\Website\OtWebsiteRepository;
use Prophecy\PhpUnit\ProphecyTrait;
use TYPO3\CMS\Core\Database\ConnectionPool;

class OtWebsiteRepositoryTest extends UnitTestCase
{
    use ProphecyTrait;

    protected $connectionPool;
    protected $pageFixtures;
    protected $websiteFixtures;
    protected $otWebsiteRepository;

    public function setUp(): void
    {
        // Prophecies to be injected in the under test OtPageRepository
        $this->connectionPool = $this->prophesize(ConnectionPool::class);

        // Fixtures
        $this->pageFixtures = new PageFixtures();
        $this->websiteFixtures = new WebsiteFixtures();

        // The under test OtWebsiteRepository
        $this->otWebsiteRepository = new OtWebsiteRepository();
    }

    /**
     * Inject the prophecies instantiated at setUp into the OtPageRepository under test object
     */
    protected function injectProphecies() {
        $this->otWebsiteRepository->injectConnectionPool($this->connectionPool->reveal());
    }

    /**
     * Calling getWebsiteByUid() on a website should return the corresponding website,
     *
     * @test
     */
    public function getWebsiteByUid()
    {
        $website_uid = 1;
        $expected = $this->websiteFixtures->getByUid($website_uid);

        $prophet = new QueryBuilderProphet($expected);
        $queryBuilder = $prophet->prophesize();
        $this->connectionPool->getQueryBuilderForTable('ot_websites')->willReturn($queryBuilder);
        $this->injectProphecies();

        $actual = $this->otWebsiteRepository->getWebsiteByUid($website_uid);
        $this->assertEquals($expected, $actual);
    }

    /**
     * Calling getWebsiteByUid() on a deleted website should throw a NoSuchWebsiteException
     *
     * @test
     */
    public function getDeletedWebsiteByUid()
    {
        $prophet = new QueryBuilderProphet([]);
        $queryBuilder = $prophet->prophesize();
        $this->connectionPool->getQueryBuilderForTable('ot_websites')->willReturn($queryBuilder);
        $this->injectProphecies();

        $this->expectException(NoSuchWebsiteException::class);
        $this->otWebsiteRepository->getWebsiteByUid(-1);
    }

    /**
     * Calling getWebsiteByOrganizationId() on a website should return the corresponding website,
     *
     * @test
     */
    public function getWebsiteByOrganizationId()
    {
        $expected = $this->websiteFixtures->getByUid(1);

        $prophet = new QueryBuilderProphet($expected);
        $queryBuilder = $prophet->prophesize();
        $this->connectionPool->getQueryBuilderForTable('ot_websites')->willReturn($queryBuilder);
        $this->injectProphecies();

        $actual = $this->otWebsiteRepository->getWebsiteByOrganizationId(1);
        $this->assertEquals($expected, $actual);
    }

    /**
     * Calling getWebsiteByOrganizationId() on a deleted website should throw a NoSuchWebsiteException
     *
     * @test
     */
    public function getDeletedWebsiteByOrganizationId()
    {
        $prophet = new QueryBuilderProphet([]);
        $queryBuilder = $prophet->prophesize();
        $this->connectionPool->getQueryBuilderForTable('ot_websites')->willReturn($queryBuilder);
        $this->injectProphecies();

        $this->expectException(NoSuchWebsiteException::class);
        $this->otWebsiteRepository->getWebsiteByUid(-1);
    }

    /**
     * Calling getWebsiteRootUid() on a website should return the corresponding root page uid
     *
     * @test
     */
    public function getWebsiteRootUid() {
        $expected = 1;

        $prophet = new QueryBuilderProphet($expected);
        $queryBuilder = $prophet->prophesize();
        $this->connectionPool->getQueryBuilderForTable('pages')->willReturn($queryBuilder);
        $this->injectProphecies();

        $actual = $this->otWebsiteRepository->getWebsiteRootUid(1);
        $this->assertEquals($expected, $actual);
    }

    /**
     * Calling findRootUidForOrganization() on a website should return the corresponding root page uid
     *
     * @test
     */
    public function findRootUidForOrganization() {
        $expected = 1;

        $prophet = new QueryBuilderProphet($expected);
        $queryBuilder = $prophet->prophesize();
        $this->connectionPool->getQueryBuilderForTable('pages')->willReturn($queryBuilder);
        $this->injectProphecies();

        $actual = $this->otWebsiteRepository->findRootUidForOrganization(1);
        $this->assertEquals($expected, $actual);
    }

    /**
     * Calling findRootUidForOrganization() on a website should return the corresponding root page uid
     *
     * @test
     */
    public function findRootUidForInvalidOrganization() {
        $expected = [];

        $prophet = new QueryBuilderProphet($expected);
        $queryBuilder = $prophet->prophesize();
        $this->connectionPool->getQueryBuilderForTable('pages')->willReturn($queryBuilder);
        $this->injectProphecies();

        $this->expectException(NoSuchWebsiteException::class);
        $this->otWebsiteRepository->findRootUidForOrganization(-1);
    }

    /**
     * Calling resolveWebsiteDomain() on a website without custom_domain set
     * should return a domain of the form <subdomain>.opentalent.fr
     *
     * @test
     */
    public function resolveWebsiteDomainWithoutCustom() {
        $expected = 'em1.opentalent.fr';

        $website = $this->websiteFixtures->getByUid(1);

        $actual = $this->otWebsiteRepository->resolveWebsiteDomain($website);
        $this->assertEquals($expected, $actual);
    }

    /**
     * Calling resolveWebsiteDomain() on a website with a custom_domain set
     * should return this custom domain
     *
     * @test
     */
    public function resolveWebsiteDomainWithCustom() {
        $expected = 'musique2.net';

        $website = $this->websiteFixtures->getByUid(2);

        $actual = $this->otWebsiteRepository->resolveWebsiteDomain($website);
        $this->assertEquals($expected, $actual);
    }

    /**
     * Calling resolveWebsiteDomain() on a website without any subdomain or custom_domain set
     * should throw an InvalidWebsiteConfigurationException
     *
     * @test
     */
    public function resolveWebsiteDomainWithoutDomain() {
        $website = $this->websiteFixtures->getByUid(3);

        $this->expectException(InvalidWebsiteConfigurationException::class);
        $this->otWebsiteRepository->resolveWebsiteDomain($website);
    }

    /**
     * Calling resolveWebsiteDomain() on a website should have the same result as resolveWebsiteDomain(),
     * but with the 'https://' prefix.
     *
     * @test
     */
    public function resolveWebsiteBaseUri() {
        $expected = 'https://em1.opentalent.fr';

        $website = $this->websiteFixtures->getByUid(1);

        $actual = $this->otWebsiteRepository->resolveWebsiteBaseUri($website);
        $this->assertEquals($expected, $actual);
    }


    /**
     * Calling generateWebsiteConfiguration() should return the full configuration array
     * as it would be found in the typo3 website config.yaml
     *
     * @param int $rootUid
     * @param string $domain
     * @return array
     */
    public function generateWebsiteConfiguration(int $rootUid, string $domain): array {
        return [

        ];
    }
}
