<?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\CmsBundle\Tests\Application\ExclusionReasons;

use Ferienpass\CmsBundle\Application\ExclusionReasonEvent;
use Ferienpass\CmsBundle\Application\ExclusionReasons\AgeInvalid;
use Ferienpass\CmsBundle\Application\ExclusionReasons\AgeInvalidListener;
use Ferienpass\CoreBundle\ApplicationSystem\ApplicationSystemInterface;
use Ferienpass\CoreBundle\Entity\Offer\Base;
use Ferienpass\CoreBundle\Entity\OfferDate;
use Ferienpass\CoreBundle\Entity\Participant\ParticipantInterface;
use PHPUnit\Framework\TestCase;

final class AgeInvalidListenerTest extends TestCase
{
    protected function setUp(): void
    {
        $this->systemSettingsManager = $this->createStub(\Ferienpass\CoreBundle\Settings\SystemSettingsManager::class);
    }

    public function testDoesNothingWhenNoAgeRestrictions(): void
    {
        $offer = new Base();
        // no min/max age set

        $event = new ExclusionReasonEvent(
            $offer,
            $this->createMock(ParticipantInterface::class),
            $this->createMock(ApplicationSystemInterface::class)
        );

        $listener = new AgeInvalidListener($this->systemSettingsManager);
        $listener($event);

        $this->addToAssertionCount(1);
    }

    public function testDoesNothingWhenNoDates(): void
    {
        $offer = new Base();
        $offer->setMinAge(6);
        $offer->setMaxAge(12);
        // no dates added

        $event = new ExclusionReasonEvent(
            $offer,
            $this->createMock(ParticipantInterface::class),
            $this->createMock(ApplicationSystemInterface::class)
        );

        $listener = new AgeInvalidListener($this->systemSettingsManager);
        $listener($event);

        $this->addToAssertionCount(1);
    }

    public function testDoesNothingWhenAgeIsNull(): void
    {
        $offerDate = $this->createMock(OfferDate::class);
        $offerDate->method('getBegin')->willReturn(new \DateTime('2024-07-01'));

        $offer = new Base();
        $offer->setMinAge(6);
        $rp = new \ReflectionProperty($offer, 'dates');
        $rp->getValue($offer)->add($offerDate);

        $participant = $this->createMock(ParticipantInterface::class);
        $participant->method('getAge')->willReturn(null);

        $event = new ExclusionReasonEvent(
            $offer,
            $participant,
            $this->createMock(ApplicationSystemInterface::class)
        );

        $listener = new AgeInvalidListener($this->systemSettingsManager);
        $listener($event);

        $this->addToAssertionCount(1);
    }

    public function testThrowsAgeInvalidWhenBelowMinAge(): void
    {
        $offerDate = $this->createMock(OfferDate::class);
        $offerDate->method('getBegin')->willReturn(new \DateTime('2024-07-01'));

        $offer = new Base();
        $offer->setMinAge(10);
        $rp = new \ReflectionProperty($offer, 'dates');
        $rp->getValue($offer)->add($offerDate);

        $participant = $this->createMock(ParticipantInterface::class);
        $participant->method('getAge')->willReturn(8);
        $participant->method('getFirstname')->willReturn('Anna');

        $event = new ExclusionReasonEvent(
            $offer,
            $participant,
            $this->createMock(ApplicationSystemInterface::class)
        );

        $this->expectException(AgeInvalid::class);

        $listener = new AgeInvalidListener($this->systemSettingsManager);
        $listener($event);
    }

    public function testDoesNothingWhenAgeIsWithinRange(): void
    {
        $offerDate = $this->createMock(OfferDate::class);
        $offerDate->method('getBegin')->willReturn(new \DateTime('2024-07-01'));

        $offer = new Base();
        $offer->setMinAge(6);
        $offer->setMaxAge(12);
        $rp = new \ReflectionProperty($offer, 'dates');
        $rp->getValue($offer)->add($offerDate);

        $participant = $this->createMock(ParticipantInterface::class);
        $participant->method('getAge')->willReturn(9);
        $participant->method('getFirstname')->willReturn('Max');

        $event = new ExclusionReasonEvent(
            $offer,
            $participant,
            $this->createMock(ApplicationSystemInterface::class)
        );

        $listener = new AgeInvalidListener($this->systemSettingsManager);
        $listener($event);

        $this->addToAssertionCount(1);
    }
}
