<?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 Sso\RestBundle\Worker\IdpWs\ServiceUser\GetValidateUserIdentifier;

use FOS\RestBundle\View\View as RestView;
use Sso\RestBundle\Api\Manager as ApiManager;
use LifeStyle\Tools\RestErrorBundle\Api\Manager as ErrorApi;
use LifeStyle\Tools\RestErrorBundle\Api\Error\Errors\Index as Errors;
use GuzzleHttp\Exception\RequestException;
use Symfony\Component\HttpFoundation\Request;

/**
 * Class Handler
 * @package Sso\RestBundle\Worker\IdpWs\ServiceUser\GetValidateUserIdentifier
 */
class Handler
{
    /**
     * @var ApiManager
     */
    protected $apiM;

    /**
     *
     * @var ErrorApi
     */
    protected $errorApi;

    /**
     * @var Errors
     */
    protected $errors;

    /**
     * @var \Sso\RestBundle\ModelXml\Response\IdpWs\ServiceUser\Validate\Error\Response
     */
    protected $errorXmlEntity;

    /**
     *
     * @var \Sso\RestBundle\ModelXml\Response\IdpWs\ServiceUser\Validate\Success\Response
     */
    protected $successXmlEntity;

    /**
     * @var \Sso\RestBundle\ModelRest\Response\IdpWs\ServiceUser\Validate\UserIdentifier
     */
    protected $successEntity;

    /**
     *
     * @param ApiManager $apiM
     */
    public function __construct(ApiManager $apiM)
    {
        $this->apiM = $apiM;
        $this->errorApi = $this->apiM->errorManager();
        $this->errors = $this->errorApi->error()->errors();
    }

    /**
     *
     * @param Request $request
     * @return RestView $view
     */
    public function init(Request $request)
    {

        // first: validate input data
        $requestModelRest = $this->validateRestRequest($request);
        if ($this->errors->hasErrors()) {
            return $this->errorApi->error()->view()->getErrorsView($this->errors->getErrors());
        }

        // second: send data to xml ws
        $responseModelXmlArray = $this->sendXmlRequest($requestModelRest->getUsername(),
            $requestModelRest->getUserIdentifier());

        // third: build response
        if ($responseModelXmlArray['status']) {
            //ok
            $view = $this->buildSuccessView($responseModelXmlArray['xml']);
        } else {
            //error
            $view = $this->buildErrorView($responseModelXmlArray['xml']);
        }

        return $view;
    }

    /**
     *
     * @param Request $request
     * @return \Sso\RestBundle\ModelRest\Request\IdpWs\ServiceUser\Validate\UserIdentifier
     */
    private function validateRestRequest(Request $request)
    {
        $requestModel = $this->apiM->modelRest()->request()->idpWs()->serviceUser()->validate();
        try {
            $requestModel->setUsername($request->get('username'));
            $requestModel->setUserIdentifier($request->get('useridentifier'));
        } catch (\InvalidArgumentException $exc) {
            $this->errors->addError($exc->getCode(), $exc->getMessage(), 'external', 'InvalidArgumentException');
            $this->errors->setCode(400);
        }

        $validationErrors = $this->apiM->validator()->validate($requestModel);

        if (count($validationErrors) > 0) {
            foreach ($validationErrors as $error) {
                $message = $error->getPropertyPath() . ": " . $error->getMessage();
                $this->errors->addError(400, $message, 'external');
                $this->errors->setCode(400);
            }
        }

        return $requestModel;
    }

    /**
     *
     * @param string $username
     * @param string $userIdentifier
     * @return array
     */
    private function sendXmlRequest($username, $userIdentifier)
    {
        $requestModel = $this->apiM->modelXml()->request()->idpWs()->serviceUser()->validate($username,
            $userIdentifier);

        $options = array(
            'headers' => array(
                'API-VERSION' => '1',
                'API-CONTROLLER' => 'UserIdentifier',
                'API-ACTION' => 'Validate',
                'Content-Type' => 'text/xml; charset=UTF-8',
            ),
            'body' => $this->apiM->serializer()->serialize($requestModel, 'xml'),
        );

        try {
            $clientResponse = $this->apiM->client()->post($this->apiM->configuration()->userIdentifier()->getBaseUrl() . $this->apiM->configuration()->userIdentifier()->getServiceAction(),
                $options);
        } catch (RequestException $ex) {
            $errorResponse = $ex->getResponse()->getBody()->getContents();
            $this->apiM->logger()->error($errorResponse);

            return ['status' => false, 'xml' => $errorResponse];
        }

        return ['status' => true, 'xml' => $clientResponse->getBody()->getContents()];
    }

    /**
     *
     * @param string $xmlString
     * @return RestView $view
     */
    private function buildSuccessView($xmlString)
    {

        $this->successXmlEntity = $this->apiM->serializer()->deserialize($xmlString,
            'Sso\RestBundle\ModelXml\Response\IdpWs\ServiceUser\Validate\Success\Response', 'xml');
        $this->successEntity = $this->apiM->modelRest()->response()->idpWs()->serviceUser()->get();
        $this->successEntity->setCode(200);
        $this->successEntity->setTrackId($this->successXmlEntity->getTrackid());
        $this->successEntity->setScriptTimeSec($this->apiM->scriptTimeSeconds());
        $this->successEntity->setUserIdentifier($this->successXmlEntity->getUserIdentifier()->getGetAction()->getUserType()->getUserIdentifier());
        $this->successEntity->setSessionLifeTime($this->successXmlEntity->getUserIdentifier()->getGetAction()->getUserType()->getSessionLifetime());

        $view = RestView::create();
        $view->setData($this->successEntity)->setStatusCode(200);

        return $view;
    }

    /**
     * @param string $xmlString
     * @return RestView
     */
    private function buildErrorView($xmlString)
    {
        $this->errorXmlEntity = $this->apiM->serializer()->deserialize(
            $xmlString,
            'Sso\RestBundle\ModelXml\Response\IdpWs\ServiceUser\Validate\Error\Response',
            'xml'
        );
        $errors = $this->errorXmlEntity->getUserIdentifier()->getValidateAction()->getError();
        $this->errors->setCode(400);
        $this->errors->setTrackId($this->errorXmlEntity->getTrackId());
        $this->errors->setScriptSeconds($this->apiM->scriptTimeSeconds());
        foreach ($errors as $error) {
            $message = 'ErrorCode: ' . $error->getErrorCode() . ' ErrorRef: ' . $error->getErrorRef() . ' ShortMessage: ' . $error->getShortMessage();
            $this->errors->addError(400, $message, 'external', $error->getLongMessage());
        }

        return $this->errorApi->error()->view()->getErrorsView($this->errors->getErrors());
    }

}
