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

use Ferienpass\CoreBundle\Entity\Attendance;
use Ferienpass\CoreBundle\Entity\Offer\Base;
use Ferienpass\CoreBundle\Entity\Participant\BaseParticipant;
use Ferienpass\CoreBundle\Enum\AttendanceStatus;
use Ferienpass\CoreBundle\Message\AttendanceCreated as AttendanceCreatedEvent;
use Ferienpass\CoreBundle\Message\AttendanceStatusChanged;
use Ferienpass\CoreBundle\Notification\AttendanceNotificationChecker;
use Ferienpass\CoreBundle\NotificationHandler\AttendanceConfirmed;
use Ferienpass\CoreBundle\NotificationHandler\AttendanceCreated;
use Ferienpass\CoreBundle\NotificationHandler\AttendanceRejected;
use Ferienpass\CoreBundle\NotificationHandler\PhoneFormatter;
use Ferienpass\CoreBundle\Notifier\Notifier;
use Ferienpass\CoreBundle\Repository\AttendanceRepository;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\UriSigner;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Uid\Uuid;

final class AttendanceNotificationsTest extends TestCase
{
    // ---- AttendanceConfirmed ----

    public function testAttendanceConfirmedDoesNothingWhenNotifyFalse(): void
    {
        $notifier = $this->createMock(Notifier::class);
        $notifier->expects(self::never())->method('send');

        $handler = new AttendanceConfirmed(
            $notifier,
            $this->createMock(AttendanceRepository::class),
            $this->createMock(UrlGeneratorInterface::class),
            new PhoneFormatter(),
            new AttendanceNotificationChecker(),
        );

        $event = new AttendanceStatusChanged((string) Uuid::v7(), null, AttendanceStatus::CONFIRMED, false);
        $handler($event, Uuid::v7());
    }

    public function testAttendanceConfirmedDoesNothingWhenAttendanceNotFound(): void
    {
        $attendanceUuid = (string) Uuid::v7();
        $attendances = $this->createMock(AttendanceRepository::class);
        $attendances->method('findOneBy')->with(['uuid' => $attendanceUuid])->willReturn(null);

        $notifier = $this->createMock(Notifier::class);
        $notifier->expects(self::never())->method('send');

        $handler = new AttendanceConfirmed(
            $notifier,
            $attendances,
            $this->createMock(UrlGeneratorInterface::class),
            new PhoneFormatter(),
            new AttendanceNotificationChecker(),
        );

        $event = new AttendanceStatusChanged($attendanceUuid, null, AttendanceStatus::CONFIRMED, true);
        $handler($event, Uuid::v7());
    }

    public function testAttendanceConfirmedDoesNothingWhenNotifierReturnsNull(): void
    {
        $offer = new Base();
        $participant = new BaseParticipant();
        $attendance = new Attendance($offer, $participant);
        $attendance->setStatus(AttendanceStatus::CONFIRMED);
        $attendanceUuid = (string) Uuid::v7();

        $attendances = $this->createMock(AttendanceRepository::class);
        $attendances->method('findOneBy')->with(['uuid' => $attendanceUuid])->willReturn($attendance);

        $notifier = $this->createMock(Notifier::class);
        $notifier->method('attendanceNewlyConfirmed')->willReturn(null);
        $notifier->expects(self::never())->method('send');

        $handler = new AttendanceConfirmed(
            $notifier,
            $attendances,
            $this->createMock(UrlGeneratorInterface::class),
            new PhoneFormatter(),
            new AttendanceNotificationChecker(),
        );

        $event = new AttendanceStatusChanged($attendanceUuid, null, AttendanceStatus::CONFIRMED, true);
        $handler($event, Uuid::v7());
    }

    // ---- AttendanceCreated ----

    public function testAttendanceCreatedDoesNothingWhenNotifyFalse(): void
    {
        $notifier = $this->createMock(Notifier::class);
        $notifier->expects(self::never())->method('send');

        $handler = new AttendanceCreated(
            $notifier,
            $this->createMock(AttendanceRepository::class),
            $this->createMock(UrlGeneratorInterface::class),
            new PhoneFormatter(),
            new AttendanceNotificationChecker(),
            $this->createMock(UriSigner::class),
        );

        $event = new AttendanceCreatedEvent((string) Uuid::v7(), false);
        $handler($event, Uuid::v7());
    }

    public function testAttendanceCreatedDoesNothingWhenAttendanceNotFound(): void
    {
        $attendanceUuid = (string) Uuid::v7();
        $attendances = $this->createMock(AttendanceRepository::class);
        $attendances->method('findOneBy')->with(['uuid' => $attendanceUuid])->willReturn(null);

        $notifier = $this->createMock(Notifier::class);
        $notifier->expects(self::never())->method('send');

        $handler = new AttendanceCreated(
            $notifier,
            $attendances,
            $this->createMock(UrlGeneratorInterface::class),
            new PhoneFormatter(),
            new AttendanceNotificationChecker(),
            $this->createMock(UriSigner::class),
        );

        $event = new AttendanceCreatedEvent($attendanceUuid, true);
        $handler($event, Uuid::v7());
    }

    public function testAttendanceCreatedDoesNothingWhenNotifierReturnsNull(): void
    {
        $offer = new Base();
        $participant = new BaseParticipant();
        $attendance = new Attendance($offer, $participant);
        $attendanceUuid = (string) Uuid::v7();

        $attendances = $this->createMock(AttendanceRepository::class);
        $attendances->method('findOneBy')->with(['uuid' => $attendanceUuid])->willReturn($attendance);

        $notifier = $this->createMock(Notifier::class);
        $notifier->method('attendanceConfirmed')->willReturn(null);
        $notifier->expects(self::never())->method('send');

        $handler = new AttendanceCreated(
            $notifier,
            $attendances,
            $this->createMock(UrlGeneratorInterface::class),
            new PhoneFormatter(),
            new AttendanceNotificationChecker(),
            $this->createMock(UriSigner::class),
        );

        $event = new AttendanceCreatedEvent($attendanceUuid, true);
        $handler($event, Uuid::v7());
    }

    // ---- AttendanceRejected ----

    public function testAttendanceRejectedDoesNothingWhenNotifyFalse(): void
    {
        $notifier = $this->createMock(Notifier::class);
        $notifier->expects(self::never())->method('send');

        $handler = new AttendanceRejected(
            $notifier,
            $this->createMock(AttendanceRepository::class),
            new PhoneFormatter(),
            new AttendanceNotificationChecker(),
        );

        $event = new AttendanceStatusChanged((string) Uuid::v7(), null, AttendanceStatus::REJECTED, false);
        $handler($event, Uuid::v7());
    }

    public function testAttendanceRejectedDoesNothingWhenAttendanceNotFound(): void
    {
        $attendanceUuid = (string) Uuid::v7();
        $attendances = $this->createMock(AttendanceRepository::class);
        $attendances->method('findOneBy')->with(['uuid' => $attendanceUuid])->willReturn(null);

        $notifier = $this->createMock(Notifier::class);
        $notifier->expects(self::never())->method('send');

        $handler = new AttendanceRejected(
            $notifier,
            $attendances,
            new PhoneFormatter(),
            new AttendanceNotificationChecker(),
        );

        $event = new AttendanceStatusChanged($attendanceUuid, null, AttendanceStatus::REJECTED, true);
        $handler($event, Uuid::v7());
    }

    public function testAttendanceRejectedDoesNothingWhenNotifierReturnsNull(): void
    {
        $offer = new Base();
        $participant = new BaseParticipant();
        $attendance = new Attendance($offer, $participant);
        $attendance->setStatus(AttendanceStatus::REJECTED);
        $attendanceUuid = (string) Uuid::v7();

        $attendances = $this->createMock(AttendanceRepository::class);
        $attendances->method('findOneBy')->with(['uuid' => $attendanceUuid])->willReturn($attendance);

        $notifier = $this->createMock(Notifier::class);
        $notifier->method('attendanceRejected')->willReturn(null);
        $notifier->expects(self::never())->method('send');

        $handler = new AttendanceRejected(
            $notifier,
            $attendances,
            new PhoneFormatter(),
            new AttendanceNotificationChecker(),
        );

        $event = new AttendanceStatusChanged($attendanceUuid, null, AttendanceStatus::REJECTED, true);
        $handler($event, Uuid::v7());
    }
}
