<?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;

use Exception;
use Shopware\Plugins\ViisonDHL\Util;
use SoapClient;

/**
 * Class LocalWSDLHandler
 *
 * This class handles the local WSDL approach for GKP, Express & Retour
 * for fallback it use the online WSDL
 *
 * @package Shopware\Plugins\ViisonDHL\Classes
 */
class LocalWSDLHandler
{
    /**
     * The Local WSDL Folder, where all WSDL files are saved
     * @var string
     */
    private static $localWSDLParentFolder = 'WsdlDocuments';

    /**
     * Class private variables
     */
    private $localWSDLName;
    private $localWSDLVersion;
    private $localWsdlFolderName;
    private $soapClassName;
    private $serviceName;

    private $util;

    /**
     * LocalWSDLHandler constructor
     * @param string $serviceName The Service name for the WSDL (gkp, express, retour)
     * @param string $localWSDLName The Local WSDL file
     * @param string $localWsdlFolderName The Local WSDL Folder
     * @param string $localWSDLVersion The WSDL Version to be used
     * @param string $soapClassName THe SOAP CLass to be used, default is SoapClient
     */
    public function __construct($serviceName, $localWSDLName, $localWsdlFolderName, $localWSDLVersion, $soapClassName = 'SoapClient')
    {
        $this->util = Util::instance();
        $this->serviceName = $serviceName;
        $this->localWSDLName = $localWSDLName;
        $this->localWsdlFolderName = $localWsdlFolderName;
        $this->localWSDLVersion = $localWSDLVersion;
        $this->soapClassName = $soapClassName;
    }

    /**
     * This function is returnig the SOAP Client with linked WSDL, options & header
     *
     * @param string, $wsdlUrl URL for the WSDL as fallback for online approach
     * @param array, $soapOptions
     * @param null $soapHeader
     * @return SoapClient
     * @throws Exception
     */
    public function getSoapClient($wsdlUrl, $soapOptions, $soapHeader = null)
    {
        try {
            if (!class_exists('SOAPClient')) {
                throw new Exception('Dieses Plugin benötigt die PHP-Erweiterung "SOAPClient". Bitte wenden Sie sich an Ihren Hoster bzw. Serveradministrator, um diese zu aktivieren.');
            }

            $wsdlPath = ($this->isWsdlFileOfflineAvaible()) ? $this->getLocalWsdlParentDirPath().$this->localWSDLName : $wsdlUrl;

            return $this->getClient($wsdlPath, $soapOptions, $soapHeader);
        } catch (\SoapFault $e) {
            // Fallback if WSDL can't be called offline
            if (($e->faultcode === 'HTTP' && $e->faultstring === 'Error Fetching http headers')
                || ($e->faultcode === 'WSDL' && mb_strpos($e->faultstring, "SOAP-ERROR: Parsing WSDL: Couldn't load from") === 0)) {
                return $this->getClient($wsdlUrl, $soapOptions, $soapHeader);
            }

            throw $e;
        }
    }

    /**
     * Check if WSDL File is already saved. If not it try's to download the WSDL files and save them
     * to the corresponding folders
     * @return bool
     */
    private function isWsdlFileOfflineAvaible()
    {
        $requiredFilesForWsdl = $this->getRequiredFilesForServiceViaName();
        $success = true;

        if ($requiredFilesForWsdl === null) {
            return false;
        }

        foreach ($requiredFilesForWsdl['requiredWsdlFiles'] as $filename) {
            $success = file_exists($this->getLocalWsdlParentDirPath().$filename);
            if (!$success) {
                break;
            }
        }

        return $success;
    }

    /**
     * Get WSDL Folder Path
     * @return string
     */
    private function getLocalWsdlParentDirPath()
    {
        return dirname(__DIR__) . DIRECTORY_SEPARATOR . self::$localWSDLParentFolder . DIRECTORY_SEPARATOR . $this->localWsdlFolderName . DIRECTORY_SEPARATOR . $this->localWSDLVersion . DIRECTORY_SEPARATOR;
    }

    /**
     * Return the the Created SOAP Client
     *
     * @param string $wsdlPath
     * @param array $soapOptions
     * @param array $soapHeader
     * @return SoapClient $client
     */
    private function getClient($wsdlPath, $soapOptions, $soapHeader)
    {
        if ($wsdlPath != $this->getLocalWsdlParentDirPath().$this->localWSDLName) {
            $this->util->log('WARNING: WSDL FILES ARE NOt AVAILABLE INSIDE DHL');
        }

        $client = new $this->soapClassName($wsdlPath, $soapOptions ?: []);
        if ($soapHeader !== null) {
            $client->__setSoapHeaders($soapHeader);
        }

        return $client;
    }

    /**
     * Return all required files & URL's for the given service
     * @return array|null
     */
    private function getRequiredFilesForServiceViaName()
    {
        if ($this->serviceName === null || $this->localWSDLVersion === null || $this->localWSDLName === null) {
            $this->util->log('Parameters missing, inside handleWsdlOffline class');

            return null;
        }

        switch (mb_strtolower($this->serviceName)) {
            case 'gkp':
                $requiredFilesForService = [
                    'baseDownloadUrl' => 'https://cig.dhl.de/cig-wsdls/com/dpdhl/wsdl/geschaeftskundenversand-api/'.$this->localWSDLVersion.'/',
                    'isNameRequired' => true,
                ];
                $baseDownloadName = 'geschaeftskundenversand-api-'.$this->localWSDLVersion;
                $requiredFilesForService['requiredWsdlFiles'] = [
                    $baseDownloadName.'.wsdl',
                    $baseDownloadName.'-schema-bcs_base.xsd',
                    $baseDownloadName.'-schema-cis_base.xsd',
                ];

                return $requiredFilesForService;
            case 'express':
                return [
                    'baseName' => $this->localWSDLName,
                    'baseDownloadUrl' => 'https://wsbexpress.dhl.com/gbl/expressRateBook?WSDL',
                    'requiredWsdlFiles' => [$this->localWSDLName],
                    'isNameRequired' => false,
                ];
            case 'retour':
                $requiredFilesForService = [
                    'baseDownloadUrl' => 'https://cig.dhl.de/cig-wsdls/com/dpdhl/wsdl/pickup-api/'.$this->localWSDLVersion.'/',
                    'isNameRequired' => true,
                ];
                $baseDownloadName = 'pickup-api-'.$this->localWSDLVersion;
                $requiredFilesForService['requiredWsdlFiles'] = [
                    $baseDownloadName.'.wsdl',
                    $baseDownloadName.'-schema.xsd',
                ];

                return $requiredFilesForService;
        }
    }
}
