<?php

namespace App\Tests\Unit\Service\Mobyt;

use App\Entity\Organization\Organization;
use App\Entity\Organization\Parameters;
use App\Repository\Organization\OrganizationRepository;
use App\Service\ApiResourceBuilder\Mobyt\MobytUserStatusBuilder;
use App\Service\Mobyt\MobytService;
use PHPUnit\Framework\TestCase;

class MobytUserStatusCreatorTest extends TestCase
{
    private MobytService $mobytService;
    private OrganizationRepository $organizationRepository;

    public function setUp(): void {
        $this->mobytService = $this->getMockBuilder(MobytService::class)
            ->disableOriginalConstructor()
            ->getMock();

        $this->organizationRepository = $this->getMockBuilder(OrganizationRepository::class)
            ->disableOriginalConstructor()
            ->getMock();
    }

    /**
     * @see MobytUserStatusBuilder::getUserStatus()
     */
    public function testGetUserStatus(): void
    {
        $mobytUserStatusCreator = $this->getMockBuilder(MobytUserStatusBuilder::class)
            ->setConstructorArgs([$this->mobytService, $this->organizationRepository])
            ->setMethodsExcept(['getUserStatus'])
            ->getMock();

        $organizationId = 123;
        $mobytLogin = 'foo';
        $mobytPassword = 'bar';

        $organization = $this->getMockBuilder(Organization::class)->getMock();
        $this->organizationRepository
            ->expects($this->once())
            ->method('find')
            ->with($organizationId)
            ->willReturn($organization);

        $parameters = $this->getMockBuilder(Parameters::class)->getMock();
        $organization->expects($this->once())->method('getParameters')->willReturn($parameters);

        $parameters->expects($this->once())->method('getUsernameSMS')->willReturn($mobytLogin);
        $parameters->expects($this->once())->method('getPasswordSMS')->willReturn($mobytPassword);

        $this->mobytService
            ->expects($this->once())
            ->method('getUserStatus')
            ->with($mobytLogin, $mobytPassword)
            ->willReturn(
                [
                    'money' => 33.0,
                    'sms' => [
                        ['type' => 'N', 'quantity' => '300'],
                        ['type' => 'EE', 'quantity' => '301'],  // this type of sms should be ignored by the method
                    ],
                    'email' => null
                ]
            );

        $mobytUserStatus = $mobytUserStatusCreator->getUserStatus($organizationId);

        $this->assertEquals(
            33.0,
            $mobytUserStatus->getMoney()
        );

        // check that top-level amount is taken in account, and only it
        $this->assertEquals(
            300,
            $mobytUserStatus->getAmount()
        );
    }

    /**
     * @see MobytUserStatusBuilder::getUserStatus()
     */
    public function testGetUserStatusInvalidOrganization(): void
    {
        $mobytUserStatusCreator = $this->getMockBuilder(MobytUserStatusBuilder::class)
            ->setConstructorArgs([$this->mobytService, $this->organizationRepository])
            ->setMethodsExcept(['getUserStatus'])
            ->getMock();

        $organizationId = 123;

        $this->organizationRepository
            ->expects($this->once())
            ->method('find')
            ->with($organizationId)
            ->willReturn(null);

        $this->expectException(\RuntimeException::class);
        $this->expectExceptionMessage('Organization not found for user');

        $mobytUserStatusCreator->getUserStatus($organizationId);
    }

    /**
     * @see MobytUserStatusBuilder::getUserStatus()
     */
    public function testGetUserStatusMissingAuthInformation(): void
    {
        $mobytUserStatusCreator = $this->getMockBuilder(MobytUserStatusBuilder::class)
            ->setConstructorArgs([$this->mobytService, $this->organizationRepository])
            ->setMethodsExcept(['getUserStatus'])
            ->getMock();

        $organizationId = 123;

        $organization = $this->getMockBuilder(Organization::class)->getMock();
        $this->organizationRepository
            ->expects($this->once())
            ->method('find')
            ->with($organizationId)
            ->willReturn($organization);

        $parameters = $this->getMockBuilder(Parameters::class)->getMock();
        $organization->expects($this->once())->method('getParameters')->willReturn($parameters);

        $parameters->expects($this->once())->method('getUsernameSMS')->willReturn(null);

        $this->mobytService
            ->expects($this->never())
            ->method('getUserStatus');

        $mobytUserStatus = $mobytUserStatusCreator->getUserStatus($organizationId);

        $this->assertEquals(
            123,
            $mobytUserStatus->getOrganizationId()
        );

        $this->assertEquals(
            0,
            $mobytUserStatus->getMoney()

        );

        // check that top-level amount is taken in account, and only it
        $this->assertEquals(
            0,
            $mobytUserStatus->getAmount()
        );
    }
}
