<?php

namespace App\Tests\Unit\Service\Core;

use App\Entity\Access\Access;
use App\Entity\Core\ContactPoint;
use App\Entity\Person\Person;
use App\Enum\Core\ContactPointTypeEnum;
use App\Repository\Core\ContactPointRepository;
use App\Service\Access\Utils;
use App\Service\Core\ContactPointUtils;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;

class ContactPointUtilsTest extends TestCase
{
    private MockObject | ContactPointRepository $contactPointRepository;

    public function setUp():void
    {
        $this->contactPointRepository = $this->getMockBuilder(ContactPointRepository::class)->disableOriginalConstructor()->getMock();
    }

    /**
     * @see Utils::getPersonContactPointPrincipal()
     */
    public function testGetPersonContactPointPrincipal(): void
    {
        $person = $this->getMockBuilder(Person::class)->disableOriginalConstructor()->getMock();
        $access = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
        $access->method('getPerson')->willReturn($person);

        $contactPoint = $this->getMockBuilder(ContactPoint::class)->disableOriginalConstructor()->getMock();

        $this->contactPointRepository
            ->method('getByTypeAndPerson')
            ->with(ContactPointTypeEnum::PRINCIPAL()->getValue(), $access->getPerson())
            ->willReturn([$contactPoint]);

        $contactPointUtils = $this
            ->getMockBuilder(ContactPointUtils::class)
            ->setConstructorArgs([$this->contactPointRepository])
            ->setMethodsExcept(['getPersonContactPointPrincipal'])
            ->getMock();

        $this->assertEquals(
            $contactPoint,
            $contactPointUtils->getPersonContactPointPrincipal($access)
        );
    }

    /**
     * @see Utils::getPersonContactPointPrincipal()
     */
    public function testGetPersonContactPointPrincipalNotExisting(): void
    {
        $person = $this->getMockBuilder(Person::class)->disableOriginalConstructor()->getMock();
        $access = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
        $access->method('getPerson')->willReturn($person);

        $this->contactPointRepository
            ->method('getByTypeAndPerson')
            ->with(ContactPointTypeEnum::PRINCIPAL()->getValue(), $access->getPerson())
            ->willReturn([]);

        $contactPointUtils = $this
            ->getMockBuilder(ContactPointUtils::class)
            ->setConstructorArgs([$this->contactPointRepository])
            ->setMethodsExcept(['getPersonContactPointPrincipal'])
            ->getMock();

        $this->assertNull(
            $contactPointUtils->getPersonContactPointPrincipal($access)
        );
    }

    /**
     * @see Utils::getPersonContactPointPrincipal()
     */
    public function testGetPersonContactPointPrincipalMoreThanOne(): void {
        $person = $this->getMockBuilder(Person::class)->disableOriginalConstructor()->getMock();
        $access = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
        $access->method('getPerson')->willReturn($person);

        $contactPoint1 = $this->getMockBuilder(ContactPoint::class)->disableOriginalConstructor()->getMock();
        $contactPoint2 = $this->getMockBuilder(ContactPoint::class)->disableOriginalConstructor()->getMock();

        $this->contactPointRepository
            ->method('getByTypeAndPerson')
            ->with(ContactPointTypeEnum::PRINCIPAL()->getValue(), $access->getPerson())
            ->willReturn([$contactPoint1, $contactPoint2]);

        $contactPointUtils = $this
            ->getMockBuilder(ContactPointUtils::class)
            ->setConstructorArgs([$this->contactPointRepository])
            ->setMethodsExcept(['getPersonContactPointPrincipal'])
            ->getMock();

        $this->expectException(\RuntimeException::class);

        $contactPointUtils->getPersonContactPointPrincipal($access);
    }
}
