<?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 SimpleSAML\Module\lifestyle\Webservice\Client;

use GuzzleHttp\Client as WebserviceClient;
use GuzzleHttp\Exception\RequestException;
use SimpleSAML\Logger;
use SimpleSAML\Module\lifestyle\Webservice\Api\Configuration\Client;
use SimpleSAML\Module\lifestyle\Webservice\Cyphering\Encoder;
use SimpleSAML\Module\lifestyle\Webservice\Security\MessageDigestPasswordEncoder;

/**
 * Class Request
 *
 * @copyright  2019 Lifestyle Webconsulting GmbH
 * @link       https://www.life-style.de
 * @package SimpleSAML\Module\lifestyle\Webservice\Client
 */
class Request
{
    /**
     * @var WebserviceClient
     */
    private $client;

    /**
     * @var Encoder
     */
    private $encoder;

    /**
     * @var MessageDigestPasswordEncoder
     */
    private $passwordEncoder;

    /**
     * @var Client
     */
    private $configuration;

    /**
     * @var Response
     */
    private $response;

    /**
     * \SimpleSAML\Module\lifestyle\Webservice\Client\Request constructor.
     * @param WebserviceClient $client
     * @param Encoder $encoder
     * @param MessageDigestPasswordEncoder $passwordEncoder
     * @param Client $configuration
     * @param Response $response
     */
    public function __construct(
        WebserviceClient $client,
        Encoder $encoder,
        MessageDigestPasswordEncoder $passwordEncoder,
        Client $configuration,
        Response $response
    ) {
        $this->client = $client;
        $this->encoder = $encoder;
        $this->passwordEncoder = $passwordEncoder;
        $this->configuration = $configuration;
        $this->response = $response;
    }

    /**
     * @param string $url
     * @param string $method
     * @param string $content
     * @return string
     */
    public function send($url, $method, $content)
    {
        // Encode password
        $encodedPassword = $this->passwordEncoder->encodePassword($this->configuration->getPassword(), $this->configuration->getSalt());

        // Prepare x-wsse header
        $created = date('c');
        $nonce = substr(md5(uniqid('nonce_', true)), 0, 16);
        $nonceSixtyFour = base64_encode($nonce);
        $passwordDigest = base64_encode(sha1($nonce . $created . $encodedPassword, true));
        $xWsseHeader = sprintf(
            'UsernameToken Username="%s", PasswordDigest="%s", Nonce="%s", Created="%s"',
            $this->configuration->getUsername(),
            $passwordDigest,
            $nonceSixtyFour,
            $created
        );

        // Set request options
        $options = array(
            'headers' => array(
                'x-wsse' => $xWsseHeader,
                'servicetoken' => $this->configuration->getServiceToken(),
                'Content-Type' => 'application/x-www-form-urlencoded',
            ),
            'body' => $this->encoder->encode($content, $passwordDigest),
            'verify' => false,
        );

        // Send request
        Logger::debug('webservice-url: ' . $url);
        try {
            $webserviceResponse = $this->client->request($method, $url, $options);
        } catch (RequestException $exception) {

            // Received an error response
            return $this->response->receive($exception->getResponse());
        }

        // Received response
        return $this->response->receive($webserviceResponse);
    }
}
