<?php

namespace App\Tests\Unit\Service\Access;

use App\ApiResources\Access\AdminAccess;
use App\Entity\Access\Access;
use App\Entity\Core\ContactPoint;
use App\Entity\Organization\Organization;
use App\Entity\Person\Person;
use App\Service\Access\AdminAccessUtils;
use App\Service\Access\Utils as AccessUtils;
use App\Service\Core\ContactPointUtils;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;

class AdminAccessUtilsTest extends TestCase
{
    private MockObject | Organization $organization;
    private MockObject | Access $access;
    private MockObject | ContactPointUtils $contactPointUtils;
    private MockObject | AccessUtils $accessUtils;

    public function setUp():void
    {
        $this->organization = $this->getMockBuilder(Organization::class)->disableOriginalConstructor()->getMock();
        $this->access = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
        $this->accessUtils = $this->getMockBuilder(AccessUtils::class)->disableOriginalConstructor()->getMock();
        $this->contactPointUtils = $this->getMockBuilder(ContactPointUtils::class)->disableOriginalConstructor()->getMock();
    }

    /**
     * @see AdminAccessUtils::getAdminAccess()
     */
    public function testGetAdminAccessWithoutAdministrator(): void
    {
        $adminAccessUtils = $this->getMockBuilder(AdminAccessUtils::class)
            ->setConstructorArgs([$this->accessUtils, $this->contactPointUtils])
            ->setMethodsExcept(['getAdminAccess'])
            ->getMock();

        $this->accessUtils
            ->method('findAdminFor')
            ->with($this->organization)
            ->willReturn(null);

        $returned = $adminAccessUtils->getAdminAccess($this->organization);

        $this->assertNull($returned);
    }

    /**
     * @see AdminAccessUtils::getAdminAccess()
     */
    public function testGetAdminAccessWithoutContactPoint(): void
    {
        $adminAccessUtils = $this->getMockBuilder(AdminAccessUtils::class)
            ->setConstructorArgs([$this->accessUtils, $this->contactPointUtils])
            ->setMethodsExcept(['getAdminAccess'])
            ->getMock();

        $this->accessUtils
            ->method('findAdminFor')
            ->with($this->organization)
            ->willReturn($this->access);

        $this->contactPointUtils
            ->method('getPersonContactPointPrincipal')
            ->with($this->access)
            ->willReturn(null);

        $returned = $adminAccessUtils->getAdminAccess($this->organization);

        $this->assertNull($returned);
    }

    /**
     * @see AdminAccessUtils::getAdminAccess()
     */
    public function testGetAdminAccess(): void
    {
        $adminAccessUtils = $this->getMockBuilder(AdminAccessUtils::class)
            ->setConstructorArgs([$this->accessUtils, $this->contactPointUtils])
            ->setMethodsExcept(['getAdminAccess'])
            ->getMock();

        $person = $this->getMockBuilder(Person::class)->disableOriginalConstructor()->getMock();
        $person->method('getUsername')->willReturn('foo');

        $this->access->method('getId')->willReturn(1);
        $this->access->method('getPerson')->willReturn($person);

        $contactPoint = $this->getMockBuilder(ContactPoint::class)->disableOriginalConstructor()->getMock();
        $contactPoint->method('getEmail')->willReturn('foo@bar.net');

        $this->accessUtils
            ->method('findAdminFor')
            ->with($this->organization)
            ->willReturn($this->access);

        $this->contactPointUtils
            ->method('getPersonContactPointPrincipal')
            ->with($this->access)
            ->willReturn($contactPoint);

        $returned = $adminAccessUtils->getAdminAccess($this->organization);

        $this->assertInstanceOf(AdminAccess::class, $returned);
    }
}
