<?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.
 *
 * @author      shgb
 * @copyright   2018 Lifestyle Webconsulting GmbH
 * @link        http://www.life-style.de
 */

namespace Sso\WebserviceBundle\Services\User\Update\Request\Version5;

use JMS\Serializer\SerializerInterface;
use Sso\WebserviceBundle\ErrorHandler\ErrorHandlerInterface;
use Sso\WebserviceBundle\Services\User\Update\RequestParserInterface;
use Sso\WebserviceBundle\Services\User\Update\RequestData\Factory as RequestDataFactory;
use InvalidArgumentException;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Sso\WebserviceBundle\Api\Mapper\Index as AutoMapper;

/**
 * Class RequestParser
 *
 * @copyright   2016 Lifestyle Webconsulting GmbH
 * @link        http://www.life-style.de
 * @package     Sso\WebserviceBundle\Services\User\Show\Request\Version5
 */
final class RequestParser implements RequestParserInterface
{
    /**
     * @var SerializerInterface
     */
    private $serializer;

    /**
     * @var RequestDataFactory
     */
    private $factory;

    /**
     * @var ErrorHandlerInterface
     */
    private $errorHandler;

    /**
     * @var ValidatorInterface
     */
    private $validator;

    /**
     * @var AutoMapper
     */
    private $autoMapper;

    /**
     * RequestParser constructor.
     * @param SerializerInterface $serializer
     * @param RequestDataFactory $factory
     * @param ErrorHandlerInterface $errorHandler
     * @param ValidatorInterface $validator
     */
    public function __construct(SerializerInterface $serializer, RequestDataFactory $factory, ErrorHandlerInterface $errorHandler, ValidatorInterface $validator, AutoMapper $autoMapper)
    {
        $this->serializer = $serializer;
        $this->factory = $factory;
        $this->errorHandler = $errorHandler;
        $this->validator = $validator;
        $this->autoMapper = $autoMapper;
    }

    /**
     * @param string $content
     * @return \Sso\WebserviceBundle\Services\User\Update\RequestData\User
     */
    public function parse($content)
    {
        /** @var Request $request */
        $request = $this->serializer->deserialize($content, Request::class, 'xml');

        $user = $this->factory->user();
        if (!$this->validate($request)) {
            return $user;
        }

        $user->setUpdateData($this->getUpdateUserDTO($request));

        $userType = $request->getUser()->getUpdate()->getKey()->getKeyUserType();

        if ($identifier = $userType->getIdentifier()) {
            $user->setIdentifier($identifier);
            $request->getUser()->getUpdate()->getValue()->getUserType()->setIdentifier($identifier);

            return $user;
        }
        if ($username = $userType->getUsername()) {
            $user->setUsername($username);
            $request->getUser()->getUpdate()->getValue()->getUserType()->setIdentifier($username);

            return $user;
        }
        if ($guid = $userType->getGuid()) {
            $user->setGuid($guid);
            $request->getUser()->getUpdate()->getValue()->getUserType()->setIdentifier($guid);

            return $user;
        }
        if ($email = $userType->getEmail()) {
            $user->setEmail($email);
            $request->getUser()->getUpdate()->getValue()->getUserType()->setIdentifier($email);

            return $user;
        }

        $this->errorHandler->addError(400, 'uu2', 'uu001', 'Wrong user data', 'No valid identifier found');

        return $user;
    }

    /**
     * @param Request $request
     * @return bool
     */
    private function validate(Request $request)
    {
        $validationErrors = $this->validator->validate($request);
        if (count($validationErrors) === 0) {
            return true;
        }
        foreach ($validationErrors as $error) {
            $message = $error->getPropertyPath() . ': ' . $error->getMessage();
            $this->errorHandler->addError(400, $message, $message, $message, $message);
        }

        return false;
    }

    /**
     * @param Request $request
     * @return \Sso\WebserviceBundle\Services\User\Update\RequestData\UpdateData
     */
    private function getUpdateUserDTO(Request $request)
    {
        $updateUserData = $this->factory->updateData();
        //now fill the DTO -> it's magick
        return $this->autoMapper->modelInToModelOut($request->getUser()->getUpdate()->getValue()->getUserType(), $updateUserData);
    }
}
