<?php

declare(strict_types=1);

/*
 * This file is part of the Ferienpass package.
 *
 * (c) Richard Henkenjohann <richard@ferienpass.online>
 *
 * For more information visit the project website <https://ferienpass.online>
 * or the documentation under <https://docs.ferienpass.online>.
 */

namespace Ferienpass\CoreBundle\Tests\Repository;

use Ferienpass\CoreBundle\Entity\Tenant;
use Ferienpass\CoreBundle\Entity\TenantDomain;
use Ferienpass\CoreBundle\Fixtures\Doctrine\OrmTestCase;
use Ferienpass\CoreBundle\Repository\TenantRepository;

class TenantRepositoryTest extends OrmTestCase
{
    public function testResolvesATenantByItsHost(): void
    {
        $this->createTenant('nordhorn', ['ferienpass-nordhorn.de', 'www.ferienpass-nordhorn.de']);
        $this->createTenant('luebeck', ['ferienpass-luebeck.de']);

        $this->assertSame('nordhorn', $this->repository()->findOneByHost('www.ferienpass-nordhorn.de')?->getSlug());
        $this->assertSame('luebeck', $this->repository()->findOneByHost('ferienpass-luebeck.de')?->getSlug());
    }

    public function testAnUnknownHostResolvesToNothing(): void
    {
        $this->createTenant('nordhorn', ['ferienpass-nordhorn.de']);

        $this->assertNull($this->repository()->findOneByHost('ferienpass-elsewhere.de'));
        $this->assertNull($this->repository()->findOneByHost(''));
    }

    /**
     * The Host header carries a port and arbitrary casing; neither may decide
     * whether a tenant is found.
     */
    public function testHostMatchingIgnoresCaseAndPort(): void
    {
        $this->createTenant('nordhorn', ['ferienpass-nordhorn.de']);

        $this->assertNotNull($this->repository()->findOneByHost('Ferienpass-Nordhorn.DE'));
        $this->assertNotNull($this->repository()->findOneByHost('ferienpass-nordhorn.de:8443'));
    }

    public function testADisabledTenantIsNotServed(): void
    {
        $tenant = $this->createTenant('nordhorn', ['ferienpass-nordhorn.de']);
        $tenant->setDisabled();
        $this->em->flush();

        $this->assertNull($this->repository()->findOneByHost('ferienpass-nordhorn.de'));
    }

    public function testResolvesATenantByItsSlug(): void
    {
        $this->createTenant('nordhorn', []);

        $this->assertNotNull($this->repository()->findOneBySlug('NORDHORN'));
        $this->assertNull($this->repository()->findOneBySlug('unknown'));
    }

    /**
     * @param list<string> $hosts
     */
    private function createTenant(string $slug, array $hosts): Tenant
    {
        $tenant = new Tenant();
        $tenant->setSlug($slug);
        $tenant->setName(ucfirst($slug));

        foreach ($hosts as $host) {
            $tenant->addDomain(new TenantDomain($tenant, $host));
        }

        $this->em->persist($tenant);
        $this->em->flush();

        return $tenant;
    }

    private function repository(): TenantRepository
    {
        $repository = $this->em->getRepository(Tenant::class);
        \assert($repository instanceof TenantRepository);

        return $repository;
    }
}
