<?php

declare(strict_types=1);

/*
 * This file is part of the Serenity package.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Serenity\CoreBundle\Test\Application\Notification\UseCase\Handler;

use PHPUnit\Framework\TestCase;
use Serenity\CoreBundle\Notification\Command\NotificationCommand;
use Serenity\CoreBundle\Notification\Command\NotificationCommandHandler;
use Serenity\CoreBundle\Notification\Enum\PushChannel;
use Serenity\CoreBundle\Notification\Enum\PushLevel;
use Serenity\CoreBundle\Notification\Enum\PushTarget;
use Serenity\CoreBundle\Notification\Enum\PushTransport;
use Serenity\CoreBundle\Notification\Enum\PushType;
use Serenity\CoreBundle\Notification\Notifier\NotifierInterface;

final class PushCommandHandlerTest extends TestCase
{
    public function testItDelegatesPushToNotifierSupportingTransport(): void
    {
        $mercureNotifier = new MercureNotifierStub();
        $flashNotifier = new FlashNotifierStub();

        $handler = new NotificationCommandHandler([$flashNotifier, $mercureNotifier]);
        $handler(new NotificationCommand(message: 'Hello', transport: PushTransport::MERCURE));

        self::assertTrue($mercureNotifier->called);
        self::assertSame('Hello', $mercureNotifier->message);
        self::assertSame(PushChannel::NOTIFIER, $mercureNotifier->channel);
        self::assertSame(PushTarget::WINDOW, $mercureNotifier->target);
        self::assertSame(PushLevel::SUCCESS, $mercureNotifier->level);
        self::assertSame(PushTransport::MERCURE, $mercureNotifier->transport);
        self::assertSame(PushType::ADMIN, $mercureNotifier->type);
        self::assertSame('@stream/notifier/alert/admin.stream.html.twig', $mercureNotifier->template);

        self::assertFalse($flashNotifier->called);
    }

    public function testItThrowsWhenNoNotifierSupportsTransport(): void
    {
        $this->expectException(\InvalidArgumentException::class);
        $this->expectExceptionMessage('No notifier supports push transport "mercure".');

        $handler = new NotificationCommandHandler([new FlashNotifierStub()]);
        $handler(new NotificationCommand(message: 'Hello', transport: PushTransport::MERCURE));
    }
}

final class MercureNotifierStub implements NotifierInterface
{
    public bool $called = false;
    public ?string $message = null;
    public ?PushChannel $channel = null;
    public ?PushTarget $target = null;
    public ?PushLevel $level = null;
    public ?PushTransport $transport = null;
    public ?PushType $type = null;
    public ?string $template = null;

    public function push(
        string $message,
        PushChannel $channel,
        PushTarget $target,
        PushLevel $level,
        PushTransport $transport,
        PushType $type,
        ?string $template = null,
    ): void {
        $this->called = true;
        $this->message = $message;
        $this->channel = $channel;
        $this->target = $target;
        $this->level = $level;
        $this->transport = $transport;
        $this->type = $type;
        $this->template = $template;
    }

    public static function supports(): PushTransport
    {
        return PushTransport::MERCURE;
    }
}

final class FlashNotifierStub implements NotifierInterface
{
    public bool $called = false;

    public function push(
        string $message,
        PushChannel $channel,
        PushTarget $target,
        PushLevel $level,
        PushTransport $transport,
        PushType $type,
        ?string $template = null,
    ): void {
        $this->called = true;
    }

    public static function supports(): PushTransport
    {
        return PushTransport::FLASH;
    }
}
