<?php

/**
 * Lifestyle Webconsulting GmbH
 *
 * LICENSE: This Software is the property of Lifestyle Webconsulting GmbH (Aschaffenburg, Germany)
 * and is private by copyright law - it is NOT Freeware.
 *
 * Any unauthorized use of this software without a valid license
 * is a violation of the license agreement and will be prosecuted by
 * civil and criminal law.
 *
 * @copyright  2018 Lifestyle Webconsulting GmbH
 * @link       http://www.life-style.de
 */

namespace LifeStyle\SamlAuthBundle\Tests\Security\Authentication\Provider;

use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use LifeStyle\SamlAuthBundle\Database\Manager as DatabaseManager;
use LifeStyle\SamlAuthBundle\Database\Data\Factory as DatabaseDataFactory;
use LifeStyle\SamlAuthBundle\Database\Data\User\Index as DatabaseDataUser;
use LifeStyle\SamlAuthBundle\Security\Authentication\Provider\SamlProvider;
use LifeStyle\SamlAuthBundle\Security\Authentication\Token\SamlToken;
use LifeStyle\SamlAuthBundle\Security\User\SamlUserProvider;
use LifeStyle\SamlAuthBundle\Model\UserData\User as UserDto;
use LifeStyle\SamlAuthBundle\Configuration\SamlConfig;
use PHPUnit_Framework_TestCase;

/**
 * Class SamlProviderTest
 * @package LifeStyle\SamlAuthBundle\Tests\Security\Authentication\Provider
 */
class SamlProviderTest extends PHPUnit_Framework_TestCase
{
    /**
     * @var UserProviderInterface|\PHPUnit_Framework_MockObject_MockObject
     */
    private $userProvider;

    /**
     * @var DatabaseManager|\PHPUnit_Framework_MockObject_MockObject
     */
    private $mockDatabase;

    /**
     * @var DatabaseDataUser|\PHPUnit_Framework_MockObject_MockObject
     */
    protected $mockDatabaseDataUser;

    /**
     * @var SamlToken
     */
    private $token;

    public function testAuthenticateSuccess()
    {
        $provider = new SamlProvider(
            $this->userProvider,
            $this->mockDatabase
        );

        $this->mockDatabaseDataUser
            ->expects($this->once())
            ->method('updateUserLogin');

        $this->assertInstanceOf(SamlToken::class, $provider->authenticate($this->token));
    }

    public function testAuthenticateFailed()
    {
        $provider = new SamlProvider(
            $this->userProvider,
            $this->mockDatabase
        );

        $this->setNoRolesToken();

        //$this->expectException(AuthenticationException::class);

        $this->mockDatabaseDataUser
            ->expects($this->once())
            ->method('updateUserLogin');

        $provider->authenticate($this->token);
    }

    public function testAuthenticateWrongProvider()
    {
        $mockProvider = $this->getMockBuilder(UserProviderInterface::class)
            ->getMock();

        $provider = new SamlProvider(
            $mockProvider,
            $this->mockDatabase
        );

        $this->expectException(AuthenticationException::class);

        $this->assertInstanceOf(SamlToken::class, $provider->authenticate($this->token));
    }

    public function testSupports()
    {
        $provider = new SamlProvider(
            $this->userProvider,
            $this->mockDatabase
        );

        $this->assertTrue($provider->supports($this->token));
    }

    public function testSupportsNot()
    {
        $provider = new SamlProvider(
            $this->userProvider,
            $this->mockDatabase
        );

        $mockToken = $this->getMockBuilder(TokenInterface::class)
            ->getMock();

        $this->assertFalse($provider->supports($mockToken));
    }

    public function setUp()
    {
        $conf = new SamlConfig();
        $this->userProvider = new SamlUserProvider($conf);

        $this->mockDatabaseDataUser = $this->getMockBuilder(DatabaseDataUser::class)
            ->disableOriginalConstructor()
            ->getMock();

        $dbDataFactory = $this->getMockBuilder(DatabaseDataFactory::class)
            ->disableOriginalConstructor()
            ->getMock();
        $dbDataFactory
            ->method('user')
            ->willReturn($this->mockDatabaseDataUser);

        $this->mockDatabase = $this->getMockBuilder(DatabaseManager::class)
            ->disableOriginalConstructor()
            ->getMock();
        $this->mockDatabase
            ->method('data')
            ->willReturn($dbDataFactory);

        $this->setValidToken();
    }

    private function setValidToken()
    {
        $user = new UserDto();
        $user
            ->setEmail('test@test.tst')
            ->setFirstname('firstname')
            ->setLastname('lastname')
            ->setUserApplicationJSONs(['....'])  // TODO: set proper (test) JSON string(s) here
            ->setUserApplications(['....'])  // TODO: set proper (test)application(s) here
            ->setUsername('testuser');
        $this->token = new SamlToken();
        $this->token->email = 'test@test.tst';
        $this->token->firstname = 'firstname';
        $this->token->lastname = 'lastname';
        $this->token->userId = '42';
        $this->token->userData = $user;
    }

    private function setNoRolesToken()
    {
        $user = new UserDto();
        $user
            ->setEmail('test@test.tst')
            ->setFirstname('firstname')
            ->setLastname('lastname')
            ->setUserApplicationJSONs([])
            ->setUserApplications([])
            ->setUsername('testuser');
        $this->token = new SamlToken();
        $this->token->email = 'test@test.tst';
        $this->token->firstname = 'firstname';
        $this->token->lastname = 'lastname';
        $this->token->userId = '42';
        $this->token->userData = $user;
    }
}
