<?php
/**
 * Class ResponseTest
 *
 * LICENSE: This Software is the property of Lifestyle Webconsulting GmbH (Aschaffenburg, Germany)
 * and is protected 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  2016 Lifestyle Webconsulting GmbH
 * @link       http://www.life-style.de
 */

namespace Sso\RestBundle\Tests\ModelRest\Response\UserWs\Version2\UserApplicationRole\Show;

use Sso\RestBundle\Api\Manager as ApiManager;
use Sso\RestBundle\ModelRest\Response\UserWs\Version2\UserApplicationRole\Show;
use Faker\Factory as FakerFactory;
use Faker\Generator as FakerGenerator;
use JMS\Serializer\Serializer;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

/**
 * Class ResponseTest
 * @package Sso\RestBundle\Tests\ModelRest\Response\UserWs\Version2\UserApplicationRole
 */
class ResponseTest extends WebTestCase
{
    /**
     * @var Serializer
     */
    private $serializer;

    /**
     * @var ApiManager
     */
    private $apiManager;

    /**
     * @var FakerGenerator
     */
    private $faker;

    /**
     * @var Show\Response
     */
    private $errorResponse;

    /**
     * @var Show\Response
     */
    private $successResponse;

    /**
     * @var string
     */
    private $dateFormat;

    protected function setUp()
    {
        parent::setUp();
        static::bootKernel();
        $this->apiManager = new ApiManager(static::$kernel->getContainer());
        $this->serializer = $this->apiManager->serializer();
        $this->faker = FakerFactory::create();

        $this->dateFormat = 'Y-m-d\TH:i:sP';

        $this->setUpErrorDataFixtures();
        $this->setUpSuccessDataFixtures();
    }

    private function setUpErrorDataFixtures()
    {
        $response = new Show\Response();
        $userType = new Show\UserType();
        $error = new Show\Error();

        $error->setCode(400)
            ->setMessage('ErrorCode: u001 ErrorRef: u2016 ShortMessage: Invalid user')
            ->setException('external');
        $userType->setCode(404)
            ->setStatus('Not Found')
            ->setError($error);
        $response->addUserType($userType)
            ->setCode(400)
            ->setStatus('Bad request')
            ->setTrackId('b4cea79f2a')
            ->setDate(new \DateTime('2016-11-09T09:16:04+01:00'))
            ->setScriptTimeSec(2.1917);

        $this->errorResponse = $response;
    }

    private function setUpSuccessDataFixtures()
    {
        $response = new Show\Response();
        $userType = new Show\UserType();
        $applicationType = new Show\ApplicationType();
        $roleType1 = new Show\RoleType();
        $roleType2 = new Show\RoleType();

        $roleType1->setName($this->faker->name)
            ->setActive((string)$this->faker->numberBetween(0, 1));

        $roleType2->setName($this->faker->name)
            ->setActive((string)$this->faker->numberBetween(0, 1));

        $applicationType->setName($this->faker->name)
            ->setActive((string)$this->faker->numberBetween(0, 1))
            ->setRole($roleType1)
            ->setRole($roleType2);

        $userType->setCode($this->faker->numberBetween(100, 300))
            ->setStatus($this->faker->word)
            ->setActive((string)$this->faker->numberBetween(0, 1))
            ->setAuthId($this->faker->numberBetween(100, 300))
            ->setCreatedAt($this->faker->dateTime)
            ->setUpdatedAt($this->faker->dateTime)
            ->setLastLoginAt($this->faker->dateTime)
            ->setLastName($this->faker->lastName)
            ->setFirstName($this->faker->firstName)
            ->setGuid($this->faker->uuid)
            ->setDeleted((string)$this->faker->numberBetween(0, 1))
            ->setEmail($this->faker->email)
            ->setUsername($this->faker->userName)
            ->setMfaEnabled((string)$this->faker->numberBetween(0, 1))
            ->setLdapSearchAttributes($this->faker->word)
            ->setLdapSearchValue($this->faker->word)
            ->setApplicationType($applicationType);

        $response->setCode($this->faker->numberBetween(100, 300))
            ->setStatus($this->faker->word)
            ->setTrackId($this->faker->word)
            ->setDate($this->faker->dateTime)
            ->setScriptTimeSec(1.234)
            ->addUserType($userType);

        $this->successResponse = $response;
    }

    public function testGetAndAddUserType()
    {
        $response = new Show\Response();
        $userType = new Show\UserType();

        $response->addUserType($userType);

        static::assertNotEmpty($response->getUserType());
        static::assertEquals($response->getUserType()->get(0), $userType);
    }

    public function testJSONSerializeError()
    {
        static::assertJsonStringEqualsJsonString(
            $this->serializer->serialize($this->errorResponse, 'json'),
            $this->getSerializedResponseErrorContent('json')
        );
    }

    public function testXMLSerializeError()
    {
        static::assertXmlStringEqualsXmlString(
            $this->serializer->serialize($this->errorResponse, 'xml'),
            $this->getSerializedResponseErrorContent('xml')
        );
    }

    public function testJSONSerializeSuccess()
    {
        static::assertJsonStringEqualsJsonString(
            $this->serializer->serialize($this->successResponse, 'json'),
            $this->getSerializedResponseSuccessContent('json')
        );
    }

    public function testXMLSerializeSuccess()
    {
        static::assertXmlStringEqualsXmlString(
            $this->serializer->serialize($this->successResponse, 'xml'),
            $this->getSerializedResponseSuccessContent('xml')
        );
    }

    /**
     * @param string $type (xml | json)
     *
     * @return string
     */
    private function getSerializedResponseSuccessContent($type = 'xml')
    {
        switch ($type) {
            case 'json':
                return <<< JSON
{
    "code": {$this->successResponse->getCode()},
    "status": "{$this->successResponse->getStatus()}",
    "trackId": "{$this->successResponse->getTrackId()}",
    "date": "{$this->successResponse->getDate()->format(\DateTime::ATOM)}",
    "scriptTimeSec": {$this->successResponse->getScriptTimeSec()},
    "userTypes": [
        {
            "code": {$this->successResponse->getUserType()->get(0)->getCode()},
            "status": "{$this->successResponse->getUserType()->get(0)->getStatus()}",
            "guid": "{$this->successResponse->getUserType()->get(0)->getGuid()}",
            "username": "{$this->successResponse->getUserType()->get(0)->getUsername()}",
            "email": "{$this->successResponse->getUserType()->get(0)->getEmail()}",
            "firstname": "{$this->successResponse->getUserType()->get(0)->getFirstname()}",
            "lastname": "{$this->successResponse->getUserType()->get(0)->getLastname()}",
            "active": "{$this->successResponse->getUserType()->get(0)->getActive()}",
            "deleted": "{$this->successResponse->getUserType()->get(0)->getDeleted()}",
            "createdAt": "{$this->successResponse->getUserType()->get(0)->getCreatedAt()->format($this->dateFormat)}",
            "lastLoginAt": "{$this->successResponse->getUserType()->get(0)->getLastLoginAt()->format($this->dateFormat)}",
            "updatedAt": "{$this->successResponse->getUserType()->get(0)->getUpdatedAt()->format($this->dateFormat)}",
            "authId": "{$this->successResponse->getUserType()->get(0)->getAuthId()}",
            "ldapSearchAttributes": "{$this->successResponse->getUserType()->get(0)->getLdapSearchAttributes()}",
            "ldapSearchValue": "{$this->successResponse->getUserType()->get(0)->getLdapSearchValue()}",
            "mfaEnabled": "{$this->successResponse->getUserType()->get(0)->getMfaEnabled()}",
            "applicationType": {
                "name": "{$this->successResponse->getUserType()->get(0)->getApplicationType()->getName()}",
                "active": "{$this->successResponse->getUserType()->get(0)->getApplicationType()->getActive()}",
                "roleType": [
                    {
                        "name": "{$this->successResponse->getUserType()->get(0)->getApplicationType()->getRole()->get(0)->getName()}",
                        "active": "{$this->successResponse->getUserType()->get(0)->getApplicationType()->getRole()->get(0)->getActive()}"
                    },
                    {
                        "name": "{$this->successResponse->getUserType()->get(0)->getApplicationType()->getRole()->get(1)->getName()}",
                        "active": "{$this->successResponse->getUserType()->get(0)->getApplicationType()->getRole()->get(1)->getActive()}"
                    }
                ]
            }
        }
    ]
}
JSON;
            case 'xml':
                return <<< XML
<?xml version="1.0" encoding="UTF-8"?>
<userRoleShow>
    <code>{$this->successResponse->getCode()}</code>
    <status>
        <![CDATA[{$this->successResponse->getStatus()}]]>
    </status>
    <trackId>
        <![CDATA[{$this->successResponse->getTrackId()}]]>
    </trackId>
    <date>
        <![CDATA[{$this->successResponse->getDate()->format(\DateTime::ATOM)}]]>
    </date>
    <scriptTimeSec>{$this->successResponse->getScriptTimeSec()}</scriptTimeSec>
    <userTypes>
        <userType>
            <code>{$this->successResponse->getUserType()->get(0)->getCode()}</code>
            <status>
                <![CDATA[{$this->successResponse->getUserType()->get(0)->getStatus()}]]>
            </status>
            <guid>
                <![CDATA[{$this->successResponse->getUserType()->get(0)->getGuid()}]]>
            </guid>
            <username>
                <![CDATA[{$this->successResponse->getUserType()->get(0)->getUsername()}]]>
            </username>
            <email>
                <![CDATA[{$this->successResponse->getUserType()->get(0)->getEmail()}]]>
            </email>
            <firstname>
                <![CDATA[{$this->successResponse->getUserType()->get(0)->getFirstname()}]]>
            </firstname>
            <lastname>
                <![CDATA[{$this->successResponse->getUserType()->get(0)->getLastName()}]]>
            </lastname>
            <active>
                <![CDATA[{$this->successResponse->getUserType()->get(0)->getActive()}]]>
            </active>
            <deleted>
                <![CDATA[{$this->successResponse->getUserType()->get(0)->getDeleted()}]]>
            </deleted>
            <createdAt>
                <![CDATA[{$this->successResponse->getUserType()->get(0)->getCreatedAt()->format($this->dateFormat)}]]>
            </createdAt>
            <lastLoginAt>
                <![CDATA[{$this->successResponse->getUserType()->get(0)->getLastLoginAt()->format($this->dateFormat)}]]>
            </lastLoginAt>
            <updatedAt>
                <![CDATA[{$this->successResponse->getUserType()->get(0)->getUpdatedAt()->format($this->dateFormat)}]]>
            </updatedAt>
            <authId>
                <![CDATA[{$this->successResponse->getUserType()->get(0)->getAuthId()}]]>
            </authId>
            <ldapSearchAttributes>
                <![CDATA[{$this->successResponse->getUserType()->get(0)->getLdapSearchAttributes()}]]>
            </ldapSearchAttributes>
            <ldapSearchValue>
                <![CDATA[{$this->successResponse->getUserType()->get(0)->getLdapSearchValue()}]]>
            </ldapSearchValue>
            <mfaEnabled>
                <![CDATA[{$this->successResponse->getUserType()->get(0)->getMfaEnabled()}]]>
            </mfaEnabled>
            <applicationType>
                <name>
                    <![CDATA[{$this->successResponse->getUserType()->get(0)->getApplicationType()->getName()}]]>
                </name>
                <active>
                    <![CDATA[{$this->successResponse->getUserType()->get(0)->getApplicationType()->getActive()}]]>
                </active>
                <roleType>
                    <name>
                        <![CDATA[{$this->successResponse->getUserType()->get(0)->getApplicationType()->getRole()->get(0)->getName()}]]>
                    </name>
                    <active>
                        <![CDATA[{$this->successResponse->getUserType()->get(0)->getApplicationType()->getRole()->get(0)->getActive()}]]>
                    </active>
                </roleType>
                <roleType>
                    <name>
                        <![CDATA[{$this->successResponse->getUserType()->get(0)->getApplicationType()->getRole()->get(1)->getName()}]]>
                    </name>
                    <active>
                        <![CDATA[{$this->successResponse->getUserType()->get(0)->getApplicationType()->getRole()->get(1)->getActive()}]]>
                    </active>
                </roleType>
            </applicationType>
        </userType>
    </userTypes>
</userRoleShow>
XML;
            default:
                throw new \PHPUnit_Framework_Exception('Invalid request type (hint: not json/xml)');
        }
    }

    /**
     * @param string $type (xml | json)
     *
     * @return string
     */
    private function getSerializedResponseErrorContent($type = 'xml')
    {
        switch ($type) {
            case 'json':
                return <<< JSON
{
    "code": {$this->errorResponse->getCode()},
    "status": "{$this->errorResponse->getStatus()}",
    "trackId": "{$this->errorResponse->getTrackId()}",
    "date": "{$this->errorResponse->getDate()->format(\DateTime::ATOM)}",
    "scriptTimeSec": {$this->errorResponse->getScriptTimeSec()},
    "userTypes": [
        {
            "code": {$this->errorResponse->getUserType()->get(0)->getCode()},
            "status": "{$this->errorResponse->getUserType()->get(0)->getStatus()}",
            "errors": [
                {
                    "code": {$this->errorResponse->getUserType()->get(0)->getError()->get(0)->getCode()},
                    "message": "{$this->errorResponse->getUserType()->get(0)->getError()->get(0)->getMessage()}",
                    "exception": "{$this->errorResponse->getUserType()->get(0)->getError()->get(0)->getException()}"
                }
            ]
        }
    ]
}
JSON;
            case 'xml':
                return <<< XML
<?xml version="1.0" encoding="UTF-8"?>
<userRoleShow>
    <code>{$this->errorResponse->getCode()}</code>
    <status>
        <![CDATA[{$this->errorResponse->getStatus()}]]>
    </status>
    <trackId>
        <![CDATA[{$this->errorResponse->getTrackId()}]]>
    </trackId>
    <date>
        <![CDATA[{$this->errorResponse->getDate()->format(\DateTime::ATOM)}]]>
    </date>
    <scriptTimeSec>{$this->errorResponse->getScriptTimeSec()}</scriptTimeSec>
    <userTypes>
        <userType>
            <code>{$this->errorResponse->getUserType()->get(0)->getCode()}</code>
            <status>
                <![CDATA[{$this->errorResponse->getUserType()->get(0)->getStatus()}]]>
            </status>
            <errors>
                <error>
                    <code>{$this->errorResponse->getUserType()->get(0)->getError()->get(0)->getCode()}</code>
                    <message>
                        <![CDATA[{$this->errorResponse->getUserType()->get(0)->getError()->get(0)->getMessage()}]]>
                    </message>
                    <exception>
                        <![CDATA[{$this->errorResponse->getUserType()->get(0)->getError()->get(0)->getException()}]]>
                    </exception>
                </error>
            </errors>
        </userType>
    </userTypes>
</userRoleShow>
XML;
            default:
                throw new \PHPUnit_Framework_Exception('Invalid request type (hint: not json/xml)');
        }
    }
}
