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

use Ferienpass\CoreBundle\Entity\Offer\OfferInterface;
use Ferienpass\CoreBundle\Entity\Participant\ParticipantInterface;
use Ferienpass\CoreBundle\LiveComponent\OfferHydrationExtension;
use Ferienpass\CoreBundle\LiveComponent\ParticipantHydrationExtension;
use Ferienpass\CoreBundle\Repository\OfferRepositoryInterface;
use Ferienpass\CoreBundle\Repository\ParticipantRepositoryInterface;
use PHPUnit\Framework\TestCase;

final class HydrationExtensionsTest extends TestCase
{
    // ---- OfferHydrationExtension ----

    public function testOfferSupportsOfferInterface(): void
    {
        $offers = $this->createMock(OfferRepositoryInterface::class);
        $ext = new OfferHydrationExtension($offers);

        self::assertTrue($ext->supports(OfferInterface::class));
    }

    public function testOfferDoesNotSupportOtherClasses(): void
    {
        $offers = $this->createMock(OfferRepositoryInterface::class);
        $ext = new OfferHydrationExtension($offers);

        self::assertFalse($ext->supports(\stdClass::class));
    }

    public function testOfferHydrateReturnsNullForFalsyValue(): void
    {
        $offers = $this->createMock(OfferRepositoryInterface::class);
        $offers->expects(self::never())->method('find');

        $ext = new OfferHydrationExtension($offers);

        self::assertNull($ext->hydrate('', OfferInterface::class));
        self::assertNull($ext->hydrate(null, OfferInterface::class));
        self::assertNull($ext->hydrate(0, OfferInterface::class));
    }

    public function testOfferHydrateThrowsForUnsupportedType(): void
    {
        $offers = $this->createMock(OfferRepositoryInterface::class);
        $ext = new OfferHydrationExtension($offers);

        $this->expectException(\InvalidArgumentException::class);
        $ext->hydrate(['key' => 'no_id'], OfferInterface::class);
    }

    // ---- ParticipantHydrationExtension ----

    public function testParticipantSupportsParticipantInterface(): void
    {
        $participants = $this->createMock(ParticipantRepositoryInterface::class);
        $ext = new ParticipantHydrationExtension($participants);

        self::assertTrue($ext->supports(ParticipantInterface::class));
    }

    public function testParticipantDoesNotSupportOtherClasses(): void
    {
        $participants = $this->createMock(ParticipantRepositoryInterface::class);
        $ext = new ParticipantHydrationExtension($participants);

        self::assertFalse($ext->supports(\stdClass::class));
    }

    public function testParticipantHydrateReturnsNullForFalsyValue(): void
    {
        $participants = $this->createMock(ParticipantRepositoryInterface::class);
        $participants->expects(self::never())->method('find');

        $ext = new ParticipantHydrationExtension($participants);

        self::assertNull($ext->hydrate('', ParticipantInterface::class));
    }

    public function testParticipantHydrateThrowsForUnsupportedType(): void
    {
        $participants = $this->createMock(ParticipantRepositoryInterface::class);
        $ext = new ParticipantHydrationExtension($participants);

        $this->expectException(\InvalidArgumentException::class);
        $ext->hydrate(['key' => 'no_id'], ParticipantInterface::class);
    }
}
