<?php

namespace Velis\Test\Bpm\Workflow\Utils;

use PHPUnit\Framework\TestCase;
use Psr\SimpleCache\InvalidArgumentException;
use Velis\Bpm\Ticket\Ticket;
use Velis\Bpm\Workflow\Subject;
use Velis\Bpm\Workflow\Utils\EmailRecipientProvider;
use Velis\Exception as VelisException;
use Velis\ParameterBag;
use Velis\User;
use Velis\User\UserProvider;

/**
 * @author Jan Małysiak <jan.malysiak@velistech.com>
 */
class EmailRecipientProviderTest extends TestCase
{
    public const USER_FROM_PROVIDER_EMAIL = 'user@example.org';

    private EmailRecipientProvider $provider;

    protected function setUp(): void
    {
        $userMock = $this->createMock(User::class);
        $userMock->method('getEmail')
            ->willReturn(self::USER_FROM_PROVIDER_EMAIL);

        $userProviderMock = $this->createMock(UserProvider::class);
        $userProviderMock->method('getUsers')
            ->willReturnCallback(function (array $userIds) use ($userMock) {
                if (!empty($userIds)) {
                    return [$userMock];
                }

                return [];
            });

        $this->provider = new EmailRecipientProvider($userProviderMock);
    }

    /**
     * @param ParameterBag $params
     * @param Subject $subject
     * @param array $emails
     * @return void
     * @throws InvalidArgumentException
     * @throws VelisException
     *
     * @dataProvider provideTestDataForGetRecipientsMethod
     */
    public function testGetRecipients(ParameterBag $params, Subject $subject, array $emails): void
    {
        $recipients = $this->provider->getRecipients($params, $subject);

        self::assertEquals($emails, array_map(fn ($recipient) => $recipient->getEmail(), $recipients));
    }

    public function provideTestDataForGetRecipientsMethod(): array
    {
        $userIdParams = new ParameterBag(['user_id' => [1]]);
        $ticketParams = new ParameterBag([
            'responsible' => true,
            'reporter' => true,
            'observers' => true,
        ]);

        $operatorEmail = 'operator@example.org';
        $operatorMock = $this->createMock(User::class);
        $operatorMock->method('getEmail')
            ->willReturn($operatorEmail);

        $reporterEmail = 'reporter@example.org';
        $reporterMock = $this->createMock(User::class);
        $reporterMock->method('getEmail')
            ->willReturn($reporterEmail);

        $observerEmail = 'observer@example.org';
        $observerMock = $this->createMock(User::class);
        $observerMock->method('getEmail')
            ->willReturn($observerEmail);

        $ticketMock = $this->createMock(Ticket::class);
        $ticketMock->method('getOperator')
            ->willReturn($operatorMock);
        $ticketMock->method('getReporter')
            ->willReturn($reporterMock);
        $ticketMock->method('getObservers')
            ->willReturn([$observerMock]);

        $guestbookParams = new ParameterBag(['guestbook_person' => true]);
        $guestbookEntryMock = $this->createMock(Subject::class);
        $hostEmail = 'host@example.org';
        $guestbookEntryMock->host_email = $hostEmail;

        $ticketWithDuplicatedUsersMock = $this->createMock(Ticket::class);
        $ticketWithDuplicatedUsersMock->method('getOperator')
            ->willReturn($operatorMock);
        $ticketWithDuplicatedUsersMock->method('getReporter')
            ->willReturn($operatorMock);
        $ticketWithDuplicatedUsersMock->method('getObservers')
            ->willReturn([$operatorMock]);

        return [
            [$userIdParams, $this->createMock(Ticket::class), [self::USER_FROM_PROVIDER_EMAIL]],
            [$ticketParams, $ticketMock, [$operatorEmail, $reporterEmail, $observerEmail]],
            [$guestbookParams, $guestbookEntryMock, [$hostEmail]],
            [$ticketParams, $ticketWithDuplicatedUsersMock, [$operatorEmail]],
        ];
    }
}
