<?php

namespace MintyPHP\Tests\Module\Notifications\Listeners;

use MintyPHP\Module\Notifications\Listeners\UserDeactivatedNotificationListener;
use MintyPHP\Module\Notifications\Service\NotificationMessage;
use MintyPHP\Module\Notifications\Service\NotificationService;
use MintyPHP\Repository\Tenant\UserTenantRepositoryInterface;
use MintyPHP\Repository\User\UserReadRepositoryInterface;
use MintyPHP\Service\Access\PermissionService;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;

final class UserDeactivatedNotificationListenerTest extends TestCase
{
    private NotificationService&MockObject $notificationService;
    private UserReadRepositoryInterface&MockObject $userReadRepository;
    private UserTenantRepositoryInterface&MockObject $userTenantRepository;
    private UserDeactivatedNotificationListener $listener;

    protected function setUp(): void
    {
        $this->notificationService = $this->createMock(NotificationService::class);
        $this->userReadRepository = $this->createMock(UserReadRepositoryInterface::class);
        $this->userTenantRepository = $this->createMock(UserTenantRepositoryInterface::class);
        $this->listener = new UserDeactivatedNotificationListener(
            $this->notificationService,
            $this->userReadRepository,
            $this->userTenantRepository
        );
    }

    public function testHandleNotifiesTenantAdmins(): void
    {
        $this->userReadRepository->expects($this->once())->method('find')->with(10)->willReturn([
            'id' => 10,
            'uuid' => 'user-uuid',
            'display_name' => 'Alice',
        ]);
        $this->userReadRepository->expects($this->once())
            ->method('listPrivilegedUserIdsByPermissionKeys')
            ->with([PermissionService::USERS_UPDATE])
            ->willReturn([20, 30]);

        $this->notificationService->expects($this->exactly(2))
            ->method('createForTenantAdminUsersFromMessage')
            ->with(
                $this->callback(static fn (int $tenantId): bool => in_array($tenantId, [1, 2], true)),
                $this->callback(function (NotificationMessage $message): bool {
                    return $message->type() === 'user.deactivated'
                        && $message->link() === 'admin/users/edit/user-uuid'
                        && $message->data() === ['user_id' => 10, 'uuid' => 'user-uuid']
                        && $message->titleKey() === 'User deactivated: %s';
                }),
                5,
                $this->isArray()
            );

        $this->listener->handle('user.deactivated', [
            'user_id' => 10,
            'tenant_ids' => [1, 2],
            'actor_user_id' => 5,
        ]);
    }

    public function testHandleSkipsWhenNoTenantIsResolved(): void
    {
        $this->userReadRepository->expects($this->once())->method('find')->with(10)->willReturn([
            'id' => 10,
            'uuid' => 'user-uuid',
            'display_name' => 'Alice',
        ]);
        $this->userTenantRepository->expects($this->once())->method('listTenantIdsByUserId')->with(10)->willReturn([]);
        $this->notificationService->expects($this->never())->method('createForTenantAdminUsersFromMessage');

        $this->listener->handle('user.deactivated', ['user_id' => 10]);
    }
}
