<?php

use Neos\Flow\Configuration\ConfigurationManager;
use Neos\Flow\Configuration\Exception\InvalidConfigurationException;
use Neos\Flow\ObjectManagement\Exception\InvalidObjectException;
use Neos\Flow\ObjectManagement\ObjectManager;
use Neos\Flow\Tests\FunctionalTestCase;
use Newland\Toubiz\Api\Service\GeoLocation\NullService;
use Newland\Toubiz\Sync\Neos\Service\GeoLocationFactory;
use PHPUnit\Framework\MockObject\MockObject;

class GeoLocationFactoryTest extends FunctionalTestCase
{
    /** @var GeoLocationFactory */
    protected $subject;

    /** @var MockObject<ObjectManager> */
    protected $objectManager;

    /** @var MockObject<ConfigurationManager> */
    protected $configuration;

    public function setUp()
    {
        parent::setUp();
        $this->objectManager = $this->getMockBuilder(ObjectManager::class)
            ->setMethods([ 'get' ])
            ->disableOriginalConstructor()
            ->getMock();
        $this->configuration = $this->getMockBuilder(ConfigurationManager::class)
            ->setMethods([ 'getConfiguration' ])
            ->disableOriginalConstructor()
            ->getMock();

        $this->subject = new GeoLocationFactory();
        $this->inject($this->subject, 'configuration', $this->configuration);
        $this->inject($this->subject, 'objectManager', $this->objectManager);
    }

    public function testFetchesClassNameFromConfiguration()
    {
        $this->configuration->expects($this->once())
            ->method('getConfiguration')
            ->will($this->returnCallback(function($type, $path) {
                $this->assertEquals(ConfigurationManager::CONFIGURATION_TYPE_SETTINGS, $type);
                $this->assertEquals('foo.bar', $path);
                return NullService::class;
            }));
        $this->objectManager->expects($this->once())
            ->method('get')
            ->will($this->returnCallback(function($object) {
                $this->assertEquals(NullService::class, $object);
                return new NullService();
            }));

        $this->subject->get('foo.bar');
    }

    public function testFailsIfNoClassNameConfigured()
    {
        $this->configuration->expects($this->once())
            ->method('getConfiguration')
            ->will($this->returnValue(null));

        $this->expectException(InvalidConfigurationException::class);
        $this->subject->get('foo.var');
    }

    public function testFailsIfClassNameConfigurationInvalid()
    {
        $this->configuration->expects($this->once())
            ->method('getConfiguration')
            ->will($this->returnValue('Lalala\Lalala'));

        $this->expectException(InvalidConfigurationException::class);
        $this->subject->get('foo.var');
    }

    public function testFailsIfConfiguredClassDoesNotImplementInterface()
    {
        $this->configuration->expects($this->once())
            ->method('getConfiguration')
            ->will($this->returnValue(static::class));

        $this->expectException(InvalidObjectException::class);
        $this->subject->get('foo.var');
    }

}