<?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  2019 Lifestyle Webconsulting GmbH
 * @link       https://www.life-style.de
 */

namespace Sso\WebserviceBundle\Services\ApplicationAttribute\Add\Request\Version2;

use JMS\Serializer\Exception\Exception as SerializerException;
use JMS\Serializer\SerializerInterface;
use Sso\WebserviceBundle\ErrorHandler\ErrorHandlerInterface;
use Sso\WebserviceBundle\Exception\InvalidRequestException;
use Sso\WebserviceBundle\Services\ApplicationAttribute\Add\RequestData\ApplicationAttributeData;
use Sso\WebserviceBundle\Services\ApplicationAttribute\Add\RequestData\Factory;
use Sso\WebserviceBundle\Services\ApplicationAttribute\Add\RequestParserInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;

/**
 * Class RequestParser
 *
 * @copyright  2019 Lifestyle Webconsulting GmbH
 * @link       https://www.life-style.de
 * @package Sso\WebserviceBundle\Services\ApplicationAttribute\Add\Request\Version2
 */
class RequestParser implements RequestParserInterface
{
    /**
     * @var SerializerInterface
     */
    private $serializer;

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

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

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

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

    /**
     * @param string $content
     * @return ApplicationAttributeData
     */
    public function parse(string $content): ApplicationAttributeData
    {
        try {
            $request = $this->deserialize($content);
            $this->validate($request);
            return $this->setRequestData($request);
        } catch (InvalidRequestException $exception) {
            unset($exception);
        }

        return $this->factory->applicationAttributeData();
    }

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

    /**
     * @param string $content
     * @return Request|null
     * @throws InvalidRequestException
     */
    private function deserialize(string $content): ?Request
    {
        $request = null;

        try {
            $request = $this->serializer->deserialize($content, Request::class, 'xml');
        } catch (SerializerException $exception) {
            $this->errorHandler->addError(400, 'XmlInvalid', 'at2002', 'Invalid request', 'Error parsing request: ' . $exception->getMessage());
            throw new InvalidRequestException();
        }

        return $request instanceof Request ? $request : null;
    }

    /**
     * @param Request|null $request
     * @return ApplicationAttributeData
     */
    private function setRequestData(?Request $request): ApplicationAttributeData
    {
        $requestData = $this->factory->applicationAttributeData();

        $add = $request->getApplicationAttribute()->getAdd();

        $requestData->setApplicationName($add->getKey()->getApplicationType()->getName());
        $requestData->setAttributeName($add->getValue()->getAttributeType()->getName());
        $requestData->setAttributeType($add->getValue()->getAttributeType()->getType());
        $requestData->setAttributeDisplayType($add->getValue()->getAttributeType()->getDisplayType());

        $options = [];
        foreach ($add->getValue()->getAttributeType()->getAttributeOptions() ?? [] as $attributeOption) {
            $options[$attributeOption->getLabel()] = $attributeOption->getValue();
        }
        $requestData->setAttributeOptions(0 < count($options) ? $options : null);

        return $requestData;
    }
}
