<?php
// Copyright (c) Pickware GmbH. All rights reserved.
// This file is part of software that is released under a proprietary license.
// You must not copy, modify, distribute, make publicly available, or execute
// its contents or parts thereof without express permission by the copyright
// holder, unless otherwise permitted by law.

namespace Shopware\Plugins\ViisonDHL\Classes\DhlRetoureApi;

use Shopware\Plugins\ViisonDHL\Components\DhlHttpLogger;

class DhlRetoureApi
{
    const DHL_TEST_BASE_URL = 'https://cig.dhl.de/services/sandbox/rest/returns';
    const DHL_PRODUCTION_BASE_URL = 'https://cig.dhl.de/services/production/rest/returns';

    const DHL_TEST_PARTNER_ID = '2222222222_customer';
    const DHL_TEST_PARTNER_PASSWORD = 'uBQbZ62!ZiBiVVbhc';

    const DHL_PRODUCTION_APP_ID = 'pickware_dhl_api_3_0_1';
    const DHL_PRODUCTION_APP_TOKEN = 'dNbXgO62mYxmyJmH6HubKuHK7r6iK0';

    /**
     * @var string
     */
    private $baseUrl;

    /**
     * @var string
     */
    private $appId;

    /**
     * @var string
     */
    private $appToken;

    /**
     * @var string
     */
    private $partnerId;

    /**
     * @var string
     */
    private $partnerPassword;

    /**
     * @var DhlHttpLogger
     */
    private $httpLogger;

    private function __construct()
    {
    }

    /**
     * @param string $appId
     * @param string $appToken
     * @param DhlHttpLogger $httpLogger
     * @return self
     */
    public static function createForTestEndpoint($appId, $appToken, DhlHttpLogger $httpLogger)
    {
        $self = new self();

        $self->baseUrl = self::DHL_TEST_BASE_URL;
        $self->appId = $appId;
        $self->appToken = $appToken;
        $self->partnerId = self::DHL_TEST_PARTNER_ID;
        $self->partnerPassword = self::DHL_TEST_PARTNER_PASSWORD;
        $self->httpLogger = $httpLogger;

        return $self;
    }

    /**
     * @param string $partnerId
     * @param string $partnerPassword
     * @param DhlHttpLogger $httpLogger
     * @return self
     */
    public static function createForProductionEndpoint($partnerId, $partnerPassword, DhlHttpLogger $httpLogger)
    {
        $self = new self();

        $self->baseUrl = self::DHL_PRODUCTION_BASE_URL;
        $self->appId = self::DHL_PRODUCTION_APP_ID;
        $self->appToken = self::DHL_PRODUCTION_APP_TOKEN;
        $self->partnerId = $partnerId;
        $self->partnerPassword = $partnerPassword;
        $self->httpLogger = $httpLogger;

        return $self;
    }

    /**
     * @param DhlRetoureReturnOrder $dhlRetoureReturnOrder
     * @return DhlRetoureApiResponse
     * @throws DhlRetoureException
     */
    public function createReturnOrder(DhlRetoureReturnOrder $dhlRetoureReturnOrder)
    {
        $dhlRetoureApiResponse = $this->sendRequest(
            'POST',
            '/',
            [
                'Accept' => 'application/json',
            ],
            json_encode($dhlRetoureReturnOrder->getRequestBody())
        );
        $dhlRetoureApiResponse->assertSuccessful();

        if (!isset($dhlRetoureApiResponse['shipmentNumber']) || !isset($dhlRetoureApiResponse['labelData'])) {
            throw DhlRetoureException::unexpectedResponse($dhlRetoureApiResponse);
        }

        return $dhlRetoureApiResponse;
    }

    /**
     * @return array
     */
    private function getHeaders()
    {
        return [
            'Authorization' => 'Basic ' . base64_encode($this->appId . ':' . $this->appToken),
            'DPDHL-User-Authentication-Token' => base64_encode($this->partnerId . ':' . $this->partnerPassword),
        ];
    }

    /**
     * @param string $method
     * @param string $resource
     * @param array $headers
     * @param null $body
     * @return DhlRetoureApiResponse
     * @throws DhlRetoureException
     */
    private function sendRequest($method, $resource, $headers = [], $body = null)
    {
        $headers = array_merge([
            'Content-type' => 'application/json',
        ], $this->getHeaders(), $headers ?: []);

        $header = '';
        foreach ($headers as $headerKey => $headerValue) {
            $header .= sprintf("%s: %s\r\n", $headerKey, $headerValue);
        }

        $options = [
            'http' => [
                'header' => $header,
                'method' => $method,
                'ignore_errors' => true,
            ],
        ];
        if ($body) {
            $options['http']['content'] = $body;
        }
        if (ini_get('max_execution_time') > 10) {
            $options['http']['timeout'] = ini_get('max_execution_time') - 5;
        }
        $context = stream_context_create($options);
        $url = $this->baseUrl . $resource;
        $response = file_get_contents($url, false, $context);

        if ($response === false) {
            $this->httpLogger->logFailedRequest($url, [
                'method' => $method,
                'headers' => $headers,
                'body' => $body,
            ]);

            throw DhlRetoureException::webserviceOffline();
        }
        $this->httpLogger->logSuccessfulRequest(
            $url,
            [
                'method' => $method,
                'headers' => $headers,
                'body' => $body,
            ],
            [
                'body' => $response,
            ]
        );

        // The $http_response_header is created automatically when calling `file_get_contents()`
        return new DhlRetoureApiResponse($response, $http_response_header);
    }
}
