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

use Ferienpass\CoreBundle\Message\AttendanceCreated;
use Ferienpass\CoreBundle\Message\AttendanceStatusChanged;
use Ferienpass\CoreBundle\Message\CommitAttendances;
use Ferienpass\CoreBundle\Message\DecisionLetterDispatched;
use Ferienpass\CoreBundle\Message\DispatchMailing;
use Ferienpass\CoreBundle\Message\HostCreated;
use Ferienpass\CoreBundle\Message\LotEdition;
use Ferienpass\CoreBundle\Message\LotOffer;
use Ferienpass\CoreBundle\Message\MailingCopyMode;
use Ferienpass\CoreBundle\Message\OfferCancelled;
use Ferienpass\CoreBundle\Message\OfferRelaunched;
use Ferienpass\CoreBundle\Message\ReorderParticipantList;
use Ferienpass\CoreBundle\Message\SendMailing;
use Ferienpass\CoreBundle\Message\WithdrawAttendance;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Lock\Key;
use Symfony\Component\Uid\Uuid;

final class MoreMessagesTest extends TestCase
{
    public function testCommitAttendancesGetters(): void
    {
        $msg = new CommitAttendances('1', ['10', '20'], true);

        self::assertSame('1', $msg->getEditionId());
        self::assertSame(['10', '20'], $msg->getAttendanceIds());
        self::assertTrue($msg->shouldSendDecisions());
        self::assertNotEmpty($msg->getRelated());
    }

    public function testHostCreatedGetters(): void
    {
        $msg = new HostCreated('5', '7');

        self::assertSame('5', $msg->getHostId());
        self::assertSame('7', $msg->getUserId());
        self::assertNotEmpty($msg->getRelated());
    }

    public function testLotEditionGetters(): void
    {
        $msg = new LotEdition('3', true, false);

        self::assertSame('3', $msg->getEditionId());
        self::assertTrue($msg->shouldUseWaitlist());
        self::assertFalse($msg->shouldIgnoreMinParticipants());
        self::assertNotEmpty($msg->getRelated());
    }

    public function testLotEditionDefaults(): void
    {
        $msg = new LotEdition('3');

        self::assertTrue($msg->shouldUseWaitlist());
        self::assertFalse($msg->shouldIgnoreMinParticipants());
    }

    public function testOfferCancelledGetters(): void
    {
        $uuid = Uuid::v7();
        $msg = new OfferCancelled('99', (string) $uuid, 'Sorry!');

        self::assertSame('99', $msg->getAttendanceId());
        self::assertSame('Sorry!', $msg->getNotifyText());
        self::assertNotEmpty($msg->getRelated());
        self::assertNotEmpty($msg->groupedBy());
    }

    public function testOfferCancelledNullNotifyText(): void
    {
        $uuid = Uuid::v7();
        $msg = new OfferCancelled('99', (string) $uuid);

        self::assertNull($msg->getNotifyText());
    }

    public function testOfferRelaunchedGetters(): void
    {
        $uuid = Uuid::v7();
        $msg = new OfferRelaunched('88', (string) $uuid, 'We are back!');

        self::assertSame('88', $msg->getAttendanceId());
        self::assertSame('We are back!', $msg->getNotifyText());
        self::assertNotEmpty($msg->getRelated());
        self::assertNotEmpty($msg->groupedBy());
    }

    public function testOfferRelaunchedNullNotifyText(): void
    {
        $uuid = Uuid::v7();
        $msg = new OfferRelaunched('88', (string) $uuid);

        self::assertNull($msg->getNotifyText());
    }

    public function testWithdrawAttendanceGetters(): void
    {
        $msg = new WithdrawAttendance('42', true, false);

        self::assertSame('42', $msg->getAttendanceId());
        self::assertTrue($msg->shallReorder());
        self::assertFalse($msg->shallNotify());
        self::assertNotEmpty($msg->getRelated());
    }

    public function testAttendanceCreatedGetters(): void
    {
        $uuid = Uuid::v7();
        $msg = new AttendanceCreated('15', true, 'myhost', (string) $uuid);

        self::assertSame('15', $msg->getAttendance());
        self::assertTrue($msg->shallNotify());
        self::assertSame('myhost', $msg->getHost());
        self::assertNotNull($msg->groupedBy());
        self::assertNotEmpty($msg->getRelated());
    }

    public function testAttendanceCreatedDefaults(): void
    {
        $msg = new AttendanceCreated('15');

        self::assertTrue($msg->shallNotify());
        self::assertNull($msg->getHost());
    }

    public function testDecisionLetterDispatchedGetters(): void
    {
        $uuid = Uuid::v7();
        $msg = new DecisionLetterDispatched('user@example.com', '2', ['10', '11'], (string) $uuid);

        self::assertSame('user@example.com', $msg->getEmail());
        self::assertSame('2', $msg->getEditionId());
        self::assertSame(['10', '11'], $msg->getAttendanceIds());
        self::assertNotNull($msg->groupedBy());
        self::assertNotEmpty($msg->getRelated());
    }

    public function testAttendanceStatusChangedGetters(): void
    {
        $msg = new AttendanceStatusChanged('7', 'waiting', 'confirmed');

        self::assertSame('7', $msg->getAttendanceId());
        self::assertSame('waiting', $msg->getOldStatus());
        self::assertSame('confirmed', $msg->getNewStatus());
        self::assertNotEmpty($msg->getRelated());
    }

    public function testAttendanceStatusChangedShallNotifyAndGroupedBy(): void
    {
        $uuid = Uuid::v7();
        $msg = new AttendanceStatusChanged('7', null, 'confirmed', true, (string) $uuid);

        self::assertTrue($msg->shallNotify());
        self::assertNotEmpty($msg->groupedBy());
    }

    public function testAttendanceStatusChangedNullGroupId(): void
    {
        $msg = new AttendanceStatusChanged('7', null, 'confirmed', false);

        self::assertFalse($msg->shallNotify());
    }

    public function testReorderParticipantListGetters(): void
    {
        $msg = new ReorderParticipantList('4', true, true, false, 'group-a');

        self::assertSame('4', $msg->getOfferId());
        self::assertTrue($msg->shouldNotify());
        self::assertTrue($msg->shouldCommit());
        self::assertNotEmpty($msg->getRelated());
    }

    public function testReorderParticipantListDefaults(): void
    {
        $msg = new ReorderParticipantList('4');

        self::assertTrue($msg->shouldNotify());
        self::assertTrue($msg->shouldCommit());
    }

    public function testReorderParticipantListAlwaysReorderAndGroup(): void
    {
        $msg = new ReorderParticipantList('4', true, true, false, 'group-a');

        self::assertFalse($msg->alwaysReorder());
        self::assertSame('group-a', $msg->getGroup());
    }

    public function testReorderParticipantListAlwaysReorderTrue(): void
    {
        $msg = new ReorderParticipantList('4', true, true, true);

        self::assertTrue($msg->alwaysReorder());
        self::assertNull($msg->getGroup());
    }

    public function testDispatchMailingGetters(): void
    {
        $msg = new DispatchMailing('1', ['a@b.com'], 'Subject', 'Body', ['key' => 'val']);

        self::assertSame('1', $msg->getInvokingUserId());
        self::assertSame(['a@b.com'], $msg->getEmails());
        self::assertSame('Subject', $msg->getSubject());
        self::assertSame('Body', $msg->getContent());
        self::assertSame(['key' => 'val'], $msg->getContext());
    }

    public function testDispatchMailingOptionalFields(): void
    {
        $msg = new DispatchMailing('1', ['a@b.com'], 'Subject', 'Body', [], ['attachment.pdf'], true, ['10', '20'], ['5']);

        self::assertSame(['attachment.pdf'], $msg->getAttachments());
        self::assertTrue($msg->isWithPaymentLink());
        self::assertNotEmpty($msg->getRelated());
    }

    public function testDispatchMailingDefaultsForOptionalFields(): void
    {
        $msg = new DispatchMailing(null, [], 'S', 'B', []);

        self::assertSame([], $msg->getAttachments());
        self::assertFalse($msg->isWithPaymentLink());
        self::assertNull($msg->getInvokingUserId());
    }

    public function testLotOfferGetters(): void
    {
        $key = new Key('offer-1');
        $msg = new LotOffer('6', $key, false);

        self::assertSame('6', $msg->getOfferId());
        self::assertSame($key, $msg->getKey());
        self::assertFalse($msg->shouldUseWaitlist());
        self::assertNotEmpty($msg->getRelated());
    }

    public function testSendMailingGetters(): void
    {
        $msg = new SendMailing('user@example.com', 'My Subject', 'Hello!', ['ctx' => 1]);

        self::assertSame('user@example.com', $msg->getEmail());
        self::assertSame('My Subject', $msg->getSubject());
        self::assertSame('Hello!', $msg->getContent());
        self::assertSame(['ctx' => 1], $msg->getContext());
        self::assertSame([], $msg->getAttachments());
        self::assertNull($msg->getPayment());
    }

    public function testSendMailingWithAttachmentsAndGroupId(): void
    {
        $uuid = Uuid::v7();
        $msg = new SendMailing('u@e.com', 'S', 'C', [], ['file.pdf'], $uuid);

        self::assertSame(['file.pdf'], $msg->getAttachments());
        self::assertNotEmpty($msg->groupedBy());
        self::assertSame([], $msg->getRelated());
    }

    public function testSendMailingIsPersonalizedByDefaultAndCanBeDisabled(): void
    {
        self::assertTrue(new SendMailing('u@e.com', 'S', 'C', [])->isPersonalized());
        self::assertFalse(new SendMailing('u@e.com', 'S', 'C', [], personalized: false)->isPersonalized());
    }

    public function testSendMailingBccDefaultsToNull(): void
    {
        self::assertNull(new SendMailing('u@e.com', 'S', 'C', [])->getBcc());
        self::assertSame('me@e.com', new SendMailing('u@e.com', 'S', 'C', [], bcc: 'me@e.com')->getBcc());
    }

    public function testDispatchMailingCopyMode(): void
    {
        self::assertSame(MailingCopyMode::None, new DispatchMailing(null, [], 'S', 'B', [])->getCopyMode());
        self::assertSame(MailingCopyMode::Bcc, new DispatchMailing(null, [], 'S', 'B', [], copyMode: MailingCopyMode::Bcc)->getCopyMode());
    }
}
