<?php
namespace Backend\BaseBundle\Tests\Controller;

use Backend\BaseBundle\Controller\BaseController;
use Backend\BaseBundle\Guesser\ControllerNameGuesser;
use Backend\BaseBundle\Model;
use Backend\BaseBundle\Tests\Fixture\BackendWebTestCase;
use Symfony\Component\HttpFoundation\Session\Session;

/**
 * @group functional
 */
class BaseControllerTest  extends BackendWebTestCase
{
    public function test_getSite_is_null()
    {
        //arrange
        $site = new Model\Site();
        $site->setSlug('testslug');
        $session = $this->getMockBuilder(Session::class)
            ->disableOriginalConstructor()
            ->setMethods(array('get'))
            ->getMock();
        $session
            ->expects($this->atLeastOnce())
            ->method('get')
            ->willReturnCallback(function($key) use($site){
                $this->assertEquals('Site', $key);
                return $site;
            });

        BaseController::INTERNAL_ACTION; //autoload
        $controller = $this->getMockForAbstractClass(BaseController::class, array(), '', false, false, false, array('get'));
        $controller
            ->expects($this->atLeastOnce())
            ->method('get')
            ->willReturnCallback(function($key) use($session){
                $this->assertEquals('session', $key);
                return $session;
            });

        //act
        $result = $this->callObjectMethod($controller, 'getSite');

        //assert
        $this->assertEquals($site, $result);
    }

    public function test_getSite_iste_is_not_null()
    {
        //arrange
        $site = new Model\Site();
        $site->setSlug('testslug');
        $session = $this->getMockBuilder(Session::class)
            ->disableOriginalConstructor()
            ->setMethods(array('get'))
            ->getMock();
        $session
            ->expects($this->never())
            ->method('get')
            ->willReturnCallback(function($key) use($site){
                $this->assertEquals('Site', $key);
                return $site;
            });

        BaseController::INTERNAL_ACTION; //autoload
        $controller = $this->getMockForAbstractClass(BaseController::class, array(), '', false, false, false, array('get'));
        $controller
            ->expects($this->never())
            ->method('get')
            ->willReturnCallback(function($key) use($session){
                $this->assertEquals('session', $key);
                return $session;
            });
        $this->setObjectAttribute($controller, 'site', $site);

        //act
        $result = $this->callObjectMethod($controller, 'getSite');

        //assert
        $this->assertEquals($site, $result);
    }

    public function test___construct()
    {
        //arrange
        //act
        $controller = $this->getMockBuilder(BaseController::class)
            ->setMethods(null)
            ->getMock();
        $controllerNameGuesser = $this->getObjectAttribute($controller, 'controllerNameGuesser');

        //assert
        $this->assertInstanceOf(ControllerNameGuesser::class, $controllerNameGuesser);
    }

    public function test_getNormalizeConfig_config_is_null()
    {
        //arrange
        $controller = $this->getMockBuilder(BaseController::class)
            ->setMethods(array('normalizeConfig', 'getControllerConfig'))
            ->disableOriginalConstructor()
            ->getMock();

        $controller
            ->expects($this->once())
            ->method('getControllerConfig')
            ->willReturn(array('controllerConfig'));

        $controller
            ->expects($this->once())
            ->method('normalizeConfig')
            ->willReturnCallback(function($config){
                $this->assertEquals(array('controllerConfig'), $config);
                return array('normalizeConfig');
            });

        //act
        $result = $this->callObjectMethod($controller, 'getNormalizeConfig');

        //assert
        $this->assertEquals(array('normalizeConfig'), $result);
    }

    public function test_getNormalizeConfig_config_is_not_null()
    {
        //arrange
        $controller = $this->getMockBuilder(BaseController::class)
            ->disableOriginalConstructor()
            ->setMethods(array('normalizeConfig', 'getControllerConfig'))
            ->getMock();

        $controller
            ->expects($this->never())
            ->method('getControllerConfig')
            ->willReturn(array('controllerConfig'));

        $controller
            ->expects($this->never())
            ->method('normalizeConfig')
            ->willReturnCallback(function($config){
                $this->assertEquals(array('controllerConfig'), $config);
                return array('normalizeConfig');
            });
        $this->setObjectAttribute($controller, 'config', array('normalizeConfig'));

        //act
        $result = $this->callObjectMethod($controller, 'getNormalizeConfig');

        //assert
        $this->assertEquals(array('normalizeConfig'), $result);
    }

    public function test_generateUrlWithSlug()
    {
        //arrange
        $route = 'abcdefg';
        $parameters = array(
            'a' => 'a',
            'b' => 'b',
            'c' => 'c',
        );
        $referenceType = 'test_reference_type';
        $site = new Model\Site();
        $site->setSlug('testslug');
        $controller = $this->getMockBuilder(BaseController::class)
            ->setMethods(array('generateUrl', 'getSite'))
            ->disableOriginalConstructor()
            ->getMock();
        $controller
            ->expects($this->once())
            ->method('getSite')
            ->willReturn($site);
        $controller
            ->expects($this->once())
            ->method('generateUrl')
            ->willReturnCallback(function($routeForTest, $parametersForTest, $referenceTypeForTest) use($route, $referenceType){
                $this->assertEquals($route, $routeForTest);
                $this->assertEquals(array(
                    'a' => 'a',
                    'b' => 'b',
                    'c' => 'c',
                    'slug' => 'testslug',
                ), $parametersForTest);
                $this->assertEquals($referenceType, $referenceTypeForTest);
                return 'result_url';
            });

        //act
        $result = $controller->generateUrlWithSlug($route, $parameters, $referenceType);

        //assert
        $this->assertEquals('result_url', $result);
    }

    public function test_redirectToRouteWithSlug()
    {
        //arrange
        $route = 'test_route';
        $parameters = array(
            'a' => 'a',
            'b' => 'b',
            'c' => 'c',
        );
        $controller = $this->getMockBuilder(BaseController::class)
            ->setMethods(array('generateUrlWithSlug', 'redirect'))
            ->disableOriginalConstructor()
            ->getMock();
        $controller
            ->expects($this->once())
            ->method('generateUrlWithSlug')
            ->willReturnCallback(function($routeForTest, $parametersForTest) use($route, $parameters){
                $this->assertEquals($route, $routeForTest);
                $this->assertEquals($parameters, $parametersForTest);
                return 'test_url';
            });
        $controller
            ->expects($this->once())
            ->method('redirect')
            ->willReturnCallback(function($url){
                $this->assertEquals('test_url', $url);
                return 'test_redirect_response';
            });

        //act
        $result = $this->callObjectMethod($controller, 'redirectToRouteWithSlug', $route, $parameters);

        //assert
        $this->assertEquals('test_redirect_response', $result);
    }
}