<?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\ModelRest\Response\UserWs\Version1\UserService\PasswordConfirm;

use Sso\RestBundle\Api;
use Sso\RestBundle\ModelRest\Common\Response\UserWs\ErrorCollector\Error;
use Sso\RestBundle\ModelRest\Response\UserWs\Version1\UserService\PasswordConfirm\Response as RestResponse;
use Sso\RestBundle\ModelRest\Response\UserWs\Version1\UserService\PasswordConfirm\Response;
use Sso\RestBundle\ModelRest\Response\UserWs\Version1\UserService\PasswordConfirm\UserPasswordConfirm;
use Sso\RestBundle\ModelRest\Response\UserWs\Version1\UserService\PasswordConfirm\UserType;
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;

    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->scriptTimeSec = $this->faker->randomFloat(2);
        $this->trackId = $this->faker->md5;
        $this->date = '2099-01-01T00:00:00+00:00';
        $this->message = $this->faker->sentence(2);
    }

    public function testResponseJSONModel()
    {
        $this->assertJsonStringEqualsJsonString($this->getSuccessResponse('json'), $this->getResponseModel('json'));
    }

    public function testResponseXMLModel()
    {
        $this->assertXmlStringEqualsXmlString($this->getSuccessResponse('xml'), $this->getResponseModel('xml'));
    }

    public function testWrongResponseJSONModel()
    {
        $this->assertJsonStringEqualsJsonString($this->getWrongResponse('json'), $this->getWrongResponseModel('json'));
    }

    public function testWrongResponseXMLModel()
    {
        $this->assertXmlStringEqualsXmlString($this->getWrongResponse('xml'), $this->getWrongResponseModel('xml'));
    }

    private function getResponseModel($type = 'json')
    {
        $response = new RestResponse();
        $response
            ->setCode(200)
            ->setScriptTimeSec($this->scriptTimeSec)
            ->setTrackId($this->trackId)
            ->setDate(new \DateTime($this->date));
        $response->setUserPasswordConfirm($this->getUserPasswordConfirm());
        $responseModel = $this->serializer->serialize($response, $type);

        return $responseModel;
    }

    private function getWrongResponseModel($type = 'json')
    {
        $response = new RestResponse();
        $userPasswordConfirm = new UserPasswordConfirm();
        $userType = new UserType();
        $error = new Error();

        $error
            ->setCode(400)
            ->setMessage($this->message)
            ->setException('external');

        $userType
            ->setCode(400)
            ->setStatus('Bad Request');
        $userType->setError($error);

        $userPasswordConfirm->addUserType($userType);

        $response
            ->setCode(400)
            ->setStatus('Bad Request')
            ->setScriptTimeSec($this->scriptTimeSec)
            ->setTrackId($this->trackId)
            ->setDate(new \DateTime($this->date));
        $response->setUserPasswordConfirm($userPasswordConfirm);

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

        return $responseModel;
    }

    /**
     * @return UserPasswordConfirm
     */
    private function getUserPasswordConfirm()
    {
        $userPasswordConfirm = new UserPasswordConfirm();
        $userType = new UserType();

        $userType
            ->setCode(200)
            ->setStatus('OK');

        $userPasswordConfirm->addUserType($userType);

        return $userPasswordConfirm;
    }

    /**
     * @param string $type
     * @return string
     */
    private function getSuccessResponse($type = 'json')
    {
        if ($type === 'xml') {
            return '<?xml version="1.0" encoding="UTF-8"?>
                <userServicePasswordConfirm>
                  <code>200</code>
                  <status><![CDATA[OK]]></status>
                  <trackId><![CDATA[' . $this->trackId . ']]></trackId>
                  <date><![CDATA[' . $this->date . ']]></date>
                  <scriptTimeSec>' . $this->scriptTimeSec . '</scriptTimeSec>
                  <userPasswordConfirm>
                    <userType>
                        <code>200</code>
                        <status><![CDATA[OK]]></status>
                    </userType>
                  </userPasswordConfirm>
                </userServicePasswordConfirm>';
        } else {
            return '{
              "code": 200,
              "status": "OK",
              "trackId": "' . $this->trackId . '",
              "date": "' . $this->date . '",
              "scriptTimeSec": ' . $this->scriptTimeSec . ',
              "userPasswordConfirm": {
                "userType": [
                    {
                      "code": 200,
                      "status": "OK"
                    }
                ]
              }
            }';
        }
    }

    /**
     * @param string $type
     * @return string
     */
    private function getWrongResponse($type = 'json')
    {
        if ($type === 'xml') {
            return '<?xml version="1.0" encoding="UTF-8"?>
                <userServicePasswordConfirm>
                  <code>400</code>
                  <status><![CDATA[Bad Request]]></status>
                  <trackId><![CDATA[' . $this->trackId . ']]></trackId>
                  <date><![CDATA[' . $this->date . ']]></date>
                  <scriptTimeSec>' . $this->scriptTimeSec . '</scriptTimeSec>
                  <userPasswordConfirm>
                      <userType>
                          <code>400</code>
                          <status><![CDATA[Bad Request]]></status>
                          <errors>
                              <error>
                                  <code>400</code>
                                  <message><![CDATA[' . $this->message . ']]></message>
                                  <exception><![CDATA[external]]></exception>
                              </error>
                          </errors>
                      </userType>
                  </userPasswordConfirm>
                </userServicePasswordConfirm>';
        } else {
            return '{
                "code": 400,
                "status": "Bad Request",
                "trackId": "' . $this->trackId . '",
                "date": "' . $this->date . '",
                "scriptTimeSec": ' . $this->scriptTimeSec . ',
                "userPasswordConfirm": {
                      "userType": [
                          {
                              "code": 400,
                              "status": "Bad Request",
                              "errors": [
                                  {
                                      "code": 400,
                                      "message": "' . $this->message . '",
                                      "exception": "external"
                                  }
                              ]
                          }
                      ]
                }
            }';
        }
    }

    public function testGetters()
    {
        /** @var Response $responseModel */
        $responseModel = $this->serializer->deserialize(
            $this->getResponseModel('json'),
            Response::class,
            'json'
        );

        $userType = $responseModel->getUserPasswordConfirm()->getUserType()->get(0);

        $error = new Error();
        $error->setCode(400)->setMessage($this->message)->setException('external');
        $userType->setError($error);

        $errors = $userType->getErrors();
        $errorResponse = $errors->get(0);

        $this->assertEquals(400, $errorResponse->getCode());
        $this->assertEquals($this->message, $errorResponse->getMessage());
        $this->assertEquals('external', $errorResponse->getException());
    }
}
