<?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\EventListener;

use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Event\PrePersistEventArgs;
use Ferienpass\CoreBundle\Entity\Offer;
use Ferienpass\CoreBundle\Entity\Tenant;
use Ferienpass\CoreBundle\EventListener\TenantPersistListener;
use Ferienpass\CoreBundle\Tenant\TenantContext;
use PHPUnit\Framework\TestCase;

class TenantPersistListenerTest extends TestCase
{
    public function testStampsTheActiveTenantOnNewRows(): void
    {
        $tenant = new Tenant();
        $offer = new Offer();

        $this->listener(enabled: true, tenant: $tenant)->prePersist($this->args($offer));

        $this->assertSame($tenant, $offer->getTenant());
    }

    public function testLeavesAnExplicitlyChosenTenantAlone(): void
    {
        $chosen = new Tenant();
        $offer = new Offer();
        $offer->setTenant($chosen);

        $this->listener(enabled: true, tenant: new Tenant())->prePersist($this->args($offer));

        $this->assertSame($chosen, $offer->getTenant());
    }

    /**
     * A maintenance command runs without a tenant. The row is then owned by
     * nobody, which hides it from every tenant — the safe direction.
     */
    public function testLeavesTheTenantNullWhenNoneIsActive(): void
    {
        $offer = new Offer();

        $this->listener(enabled: true, tenant: null)->prePersist($this->args($offer));

        $this->assertNull($offer->getTenant());
    }

    public function testDoesNothingOnASingleTenantBuild(): void
    {
        $offer = new Offer();

        $this->listener(enabled: false, tenant: new Tenant())->prePersist($this->args($offer));

        $this->assertNull($offer->getTenant());
    }

    public function testIgnoresEntitiesThatDoNotBelongToATenant(): void
    {
        $this->expectNotToPerformAssertions();

        // A Tenant is not itself tenant-aware; the listener must not touch it.
        $this->listener(enabled: true, tenant: new Tenant())->prePersist($this->args(new Tenant()));
    }

    private function listener(bool $enabled, ?Tenant $tenant): TenantPersistListener
    {
        $context = $this->createMock(TenantContext::class);
        $context->method('isEnabled')->willReturn($enabled);
        $context->method('getTenant')->willReturn($tenant);

        return new TenantPersistListener($context);
    }

    private function args(object $entity): PrePersistEventArgs
    {
        return new PrePersistEventArgs($entity, $this->createStub(EntityManagerInterface::class));
    }
}
