<?php

/**
 * 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\ModelXml\Response\UserWs\Version2\UserSearch\Advanced;

use Sso\RestBundle\Api;
use Sso\RestBundle\ModelShared\Response\UserWs\Version2\UserSearch\Advanced\Success\ApplicationRoleType;
use Sso\RestBundle\ModelShared\Response\UserWs\Version2\UserSearch\Advanced\Success\ApplicationType;
use Sso\RestBundle\ModelShared\Response\UserWs\Version2\UserSearch\Advanced\Success\AttributeType;
use Sso\RestBundle\ModelShared\Response\UserWs\Version2\UserSearch\Advanced\Success\User;
use Sso\RestBundle\ModelShared\Response\UserWs\Version2\UserSearch\Advanced\Success\UserType;
use Sso\RestBundle\ModelXml\Response\UserWs\Version2\UserSearch\Advanced\Error\Error;
use Sso\RestBundle\ModelXml\Response\UserWs\Version2\UserSearch\Advanced\Success\Users;
use Sso\RestBundle\ModelXml\Response\UserWs\Version2\UserSearch\Advanced\Success\UserSearch;
use Sso\RestBundle\ModelXml\Response\UserWs\Version2\UserSearch\Advanced\Success\Advanced as SuccessAdvanced;
use Sso\RestBundle\ModelXml\Response\UserWs\Version2\UserSearch\Advanced\Success\Response as SuccessXmlResponse;
use Sso\RestBundle\ModelXml\Response\UserWs\Version2\UserSearch\Advanced\Error\Response as ErrorXmlResponse;
use Doctrine\Common\Collections\ArrayCollection;
use GuzzleHttp\Client;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Faker\Factory as FakerFactory;
use Faker\Generator as FakerGenerator;

/**
 * Class ResponseTest
 *
 * @copyright  2016 Lifestyle Webconsulting GmbH
 * @link       http://www.life-style.de
 */
class ResponseTest extends WebTestCase
{
    /**
     * @var Api\Manager
     */
    public $apiM;

    /**
     * @var Client
     */
    protected $client;

    /**
     * @var ContainerInterface
     */
    protected $container;

    /**
     * @var \JMS\Serializer\Serializer
     */
    protected $serializer;

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

    /**
     * @var float
     */
    private $scriptTimeSec;

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

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

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

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

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

    /**
     * @var integer
     */
    private $active;

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

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

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

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

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

    /**
     * @var integer
     */
    private $errorCount;

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

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

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

    /**
     * @var boolean
     */
    private $deleted;

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

    /**
     * @var integer
     */
    private $mfaEnabled;

    /**
     * @var integer
     */
    private $count;

    /**
     * @var integer
     */
    private $offset;

    /**
     * @var integer
     */
    private $limit;

    /**
     * @var integer
     */
    private $fullResponse;

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

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

    protected function setUp()
    {
        $this->client = static::createClient();
        $this->container = $this->client->getContainer();
        $this->apiM = new Api\Manager($this->container);
        $this->serializer = $this->apiM->serializer();
        $this->faker = FakerFactory::create();

        // Set same random data
        $this->trackId = $this->faker->md5;
        $this->date = '2099-01-01T00:00:00+00:00';
        $this->scriptTimeSec = $this->faker->randomFloat(2);
        $this->count = $this->faker->numberBetween(1, 10);
        $this->offset = $this->faker->numberBetween(0, 10);
        $this->limit = $this->faker->numberBetween(0, 1000);
        $this->fullResponse = $this->faker->boolean ? 1 : 0;
        $this->message = $this->faker->sentence(2);
        $this->name = $this->faker->word;
        $this->description = $this->faker->sentence();
        $this->guid = $this->faker->md5;
        $this->username = $this->faker->userName;
        $this->email = $this->faker->email;
        $this->controller = $this->faker->word;
        $this->action = $this->faker->word;
        $this->errorCount = $this->faker->randomNumber();
        $this->type = $this->faker->word;
        $this->name = $this->faker->word;
        $this->description = $this->faker->sentence();
        $this->message = $this->faker->sentence();
        $this->guid = $this->faker->uuid;
        $this->username = $this->faker->userName;
        $this->email = $this->faker->email;
        $this->firstName = $this->faker->firstName;
        $this->lastName = $this->faker->lastName;
        $this->active = $this->faker->boolean ? 1 : 0;
        $this->deleted = $this->faker->boolean ? 1 : 0;
        $this->authId = $this->faker->md5;
        $this->mfaEnabled = $this->faker->boolean ? 1 : 0;
        $this->attrValue = $this->faker->sentence(2);
        $this->orderDir = $this->faker->randomElement(['ASC', 'DESC']);
    }

    public function testSuccessResponseModel()
    {
        $this->assertXmlStringEqualsXmlString($this->getSuccessResponse(), $this->getSuccessResponseModel());
    }

    public function testErrorResponseModel()
    {
        $this->assertXmlStringEqualsXmlString($this->getErrorResponse(), $this->getErrorResponseModel());
    }

    private function getSuccessResponseModel()
    {
        $response = new SuccessXmlResponse();
        $response
            ->setCode(200)
            ->setStatus('OK')
            ->setTrackId($this->trackId)
            ->setDate(new \DateTime($this->date))
            ->setScriptTimeSec($this->scriptTimeSec);

        $userSearch = new UserSearch();
        $advanced = new SuccessAdvanced();
        $users = new Users();
        $user = new User();
        $userType = new UserType();
        $applicationType = new ApplicationType();
        $attributeType = new AttributeType();
        $applicationRoleType = new ApplicationRoleType();

        $userType
            ->setGuid($this->guid)
            ->setUsername($this->username)
            ->setEmail($this->email)
            ->setFirstname($this->firstName)
            ->setLastname($this->lastName)
            ->setActive($this->active === 1)
            ->setDeleted($this->deleted === 1)
            ->setCreatedAt(new \DateTime($this->date))
            ->setUpdatedAt(new \DateTime($this->date))
            ->setLastLoginAt(new \DateTime($this->date))
            ->setAuthId($this->authId)
            ->setLdapSearchAttributes('')
            ->setLdapSearchValue('')
            ->setMfaEnabled($this->mfaEnabled === 1);

        $attributeType
            ->setType('one')
            ->setName($this->name)
            ->setValue($this->attrValue);

        $applicationRoleType
            ->setName($this->name)
            ->setDescription($this->description)
            ->setActive($this->active);

        $applicationType
            ->setName($this->name)
            ->setActive($this->active)
            ->addAttributeType($attributeType)
            ->addApplicationRoleType($applicationRoleType);

        $user
            ->setUserType($userType)
            ->addApplicationType($applicationType);

        $users->addUser($user);
        $advanced
            ->setStatus('OK')
            ->setCount($this->count)
            ->setOffset($this->offset)
            ->setLimit($this->limit)
            ->setOrderBy('')
            ->setOrderDir($this->orderDir)
            ->setFullResponse($this->fullResponse)
            ->setUsers($users);
        $userSearch->setAdvanced($advanced);
        $response->setUserSearch($userSearch);

        $responseModel = $this->serializer->serialize($response, 'xml');

        return $responseModel;
    }

    private function getErrorResponseModel()
    {
        $response = new ErrorXmlResponse();
        $response
            ->setCode(400)
            ->setStatus('Bad Request')
            ->setTrackId($this->trackId)
            ->setController($this->controller)
            ->setAction($this->action)
            ->setDate(new \DateTime($this->date))
            ->setScriptTimeSec($this->scriptTimeSec)
            ->setErrorCount($this->errorCount);

        $error = new Error();
        $error
            ->setCode(400)
            ->setStatus('Bad Request')
            ->setErrorCode('fw003')
            ->setErrorRef('hd007')
            ->setShortMessage($this->message)
            ->setLongMessage($this->message)
            ->setType($this->type);

        $errors = new ArrayCollection();
        $errors->add($error);
        $response->setErrors($errors);

        $responseModel = $this->serializer->serialize($response, 'xml');

        return $responseModel;
    }

    /**
     * @return string
     */
    private function getSuccessResponse()
    {
        return '<?xml version="1.0" encoding="utf-8"?>
            <SsoResponse>
              <Code>200</Code>
              <Status><![CDATA[OK]]></Status>
              <Trackid><![CDATA[' . $this->trackId . ']]></Trackid>
              <Date><![CDATA[' . $this->date . ']]></Date>
              <ScriptTimeSec>' . $this->scriptTimeSec . '</ScriptTimeSec>
              <UserSearch>
                <Advanced>
                  <Status><![CDATA[OK]]></Status>
                  <Count>' . $this->count . '</Count>
                  <Offset>' . $this->offset . '</Offset>
                  <Limit>' . $this->limit . '</Limit>
                  <OrderBy><![CDATA[]]></OrderBy>
                  <OrderDir><![CDATA[' . $this->orderDir . ']]></OrderDir>
                  <FullResponse>' . $this->fullResponse . '</FullResponse>
                  <Users>
                    <User>
                      <UserType>
                        <Guid><![CDATA[' . $this->guid . ']]></Guid>
                        <Username><![CDATA[' . $this->username . ']]></Username>
                        <Email><![CDATA[' . $this->email . ']]></Email>
                        <Firstname><![CDATA[' . $this->firstName . ']]></Firstname>
                        <Lastname><![CDATA[' . $this->lastName . ']]></Lastname>
                        <Active>' . $this->active . '</Active>
                        <Deleted>' . $this->deleted . '</Deleted>
                        <CreatedAt><![CDATA[' . $this->date . ']]></CreatedAt>
                        <UpdatedAt><![CDATA[' . $this->date . ']]></UpdatedAt>
                        <LastLoginAt><![CDATA[' . $this->date . ']]></LastLoginAt>
                        <AuthId><![CDATA[' . $this->authId . ']]></AuthId>
                        <LdapSearchAttributes><![CDATA[]]></LdapSearchAttributes>
                        <LdapSearchValue><![CDATA[]]></LdapSearchValue>
                        <MfaEnabled>' . $this->mfaEnabled . '</MfaEnabled>
                      </UserType>
                      <ApplicationType>
                            <Name><![CDATA[' . $this->name . ']]></Name>
                            <Active>' . $this->active . '</Active>
                            <AttributeType>
                                 <Type><![CDATA[one]]></Type>
                                 <Name><![CDATA[' . $this->name . ']]></Name>
                                 <Value><![CDATA[' . $this->attrValue . ']]></Value>
                            </AttributeType>
                            <ApplicationRoleType>
                                 <Name><![CDATA[' . $this->name . ']]></Name>
                                 <Description><![CDATA[' . $this->description . ']]></Description>
                                 <Active>' . $this->active . '</Active>
                            </ApplicationRoleType>
                        </ApplicationType>
                       </User>
                   </Users>
                 </Advanced>
              </UserSearch>
            </SsoResponse>';
    }

    /**
     * @return string
     */
    private function getErrorResponse()
    {
        return '<?xml version="1.0" encoding="utf-8"?>
            <SsoResponse>
                <Code>400</Code>
                <Status><![CDATA[Bad Request]]></Status>
                <TrackId><![CDATA[' . $this->trackId . ']]></TrackId>
                <Controller><![CDATA[' . $this->controller . ']]></Controller>
                <Action><![CDATA[' . $this->action . ']]></Action>
                <Date><![CDATA[' . $this->date . ']]></Date>
                <ScriptTimeSec>' . $this->scriptTimeSec . '</ScriptTimeSec>
                <ErrorCount>' . $this->errorCount . '</ErrorCount>
                <Errors>
                    <Error>
                        <Code>400</Code>
                        <Status><![CDATA[Bad Request]]></Status>
                        <ErrorCode><![CDATA[fw003]]></ErrorCode>
                        <ErrorReference><![CDATA[hd007]]></ErrorReference>
                        <ShortMessage><![CDATA[' . $this->message . ']]></ShortMessage>
                        <LongMessage><![CDATA[' . $this->message . ']]></LongMessage>
                        <Type><![CDATA[' . $this->type . ']]></Type>
                    </Error>
                </Errors>
            </SsoResponse>';
    }

    public function testSuccessGetters()
    {
        /** @var SuccessXmlResponse $responseModel */
        $responseModel = $this->serializer->deserialize(
            $this->getSuccessResponseModel(),
            SuccessXmlResponse::class,
            'xml'
        );

        $userType = $responseModel->getUserSearch()->getAdvanced()->getUsers()->getUsers()[0]->getUserType();
        $applicationType = $responseModel->getUserSearch()->getAdvanced()->getUsers()->getUsers()[0]->getApplicationType()[0];
        $attributeType = $applicationType->getAttributeType()[0];
        $applicationRoleType = $applicationType->getApplicationRoleType()[0];

        $this->assertEquals(200, $responseModel->getCode());
        $this->assertEquals('OK', $responseModel->getStatus());
        $this->assertEquals($this->trackId, $responseModel->getTrackId());
        $this->assertEquals(new \DateTime($this->date), $responseModel->getDate());
        $this->assertEquals($this->scriptTimeSec, $responseModel->getScriptTimeSec());

        $this->assertEquals('OK', $responseModel->getUserSearch()->getAdvanced()->getStatus());
        $this->assertEquals($this->count, $responseModel->getUserSearch()->getAdvanced()->getCount());
        $this->assertEquals($this->offset, $responseModel->getUserSearch()->getAdvanced()->getOffset());
        $this->assertEquals($this->limit, $responseModel->getUserSearch()->getAdvanced()->getLimit());
        $this->assertEquals('', $responseModel->getUserSearch()->getAdvanced()->getOrderBy());
        $this->assertEquals($this->orderDir, $responseModel->getUserSearch()->getAdvanced()->getOrderDir());
        $this->assertEquals($this->fullResponse, $responseModel->getUserSearch()->getAdvanced()->getFullResponse());

        $this->assertEquals($this->guid, $userType->getGuid());
        $this->assertEquals($this->username, $userType->getUsername());
        $this->assertEquals($this->email, $userType->getEmail());
        $this->assertEquals($this->firstName, $userType->getFirstname());
        $this->assertEquals($this->lastName, $userType->getLastname());
        $this->assertEquals($this->active, $userType->isActive() ? 1 : 0);
        $this->assertEquals($this->deleted, $userType->isDeleted() ? 1 : 0);
        $this->assertEquals(new \DateTime($this->date), $userType->getCreatedAt());
        $this->assertEquals(new \DateTime($this->date), $userType->getUpdatedAt());
        $this->assertEquals(new \DateTime($this->date), $userType->getLastLoginAt());
        $this->assertEquals($this->authId, $userType->getAuthId());
        $this->assertEquals('', $userType->getLdapSearchAttributes());
        $this->assertEquals('', $userType->getLdapSearchValue());
        $this->assertEquals($this->mfaEnabled, $userType->isMfaEnabled() ? 1 : 0);
        $this->assertEquals($this->mfaEnabled, $userType->getMfaEnabledAsInteger());

        $this->assertEquals($this->name, $applicationType->getName());
        $this->assertEquals($this->active, $applicationType->isActive() ? 1 : 0);

        $this->assertEquals('one', $attributeType->getType());
        $this->assertEquals($this->name, $attributeType->getName());
        $this->assertEquals($this->attrValue, $attributeType->getValue());

        $this->assertEquals($this->name, $applicationRoleType->getName());
        $this->assertEquals($this->description, $applicationRoleType->getDescription());
        $this->assertEquals($this->active, $applicationRoleType->getActive());
    }

    public function testErrorGetters()
    {
        /** @var ErrorXmlResponse $responseModel */
        $responseModel = $this->serializer->deserialize(
            $this->getErrorResponseModel(),
            ErrorXmlResponse::class,
            'xml'
        );

        $error = $responseModel->getErrors()->get(0);

        $this->assertEquals(400, $responseModel->getCode());
        $this->assertEquals('Bad Request', $responseModel->getStatus());
        $this->assertEquals($this->trackId, $responseModel->getTrackId());
        $this->assertEquals($this->controller, $responseModel->getController());
        $this->assertEquals($this->action, $responseModel->getAction());
        $this->assertEquals(new \DateTime($this->date), $responseModel->getDate());
        $this->assertEquals($this->scriptTimeSec, $responseModel->getScriptTimeSec());
        $this->assertEquals($this->errorCount, $responseModel->getErrorCount());

        $this->assertEquals(400, $error->getCode());
        $this->assertEquals('Bad Request', $error->getStatus());
        $this->assertEquals('fw003', $error->getErrorCode());
        $this->assertEquals('hd007', $error->getErrorRef());
        $this->assertEquals($this->message, $error->getShortMessage());
        $this->assertEquals($this->message, $error->getLongMessage());
        $this->assertEquals($this->type, $error->getType());
    }
}
