<?php
/*
**** COPYRIGHT & LICENSE NOTICE *** DO NOT REMOVE ****
* 
* Xentral (c) Xentral ERP Sorftware GmbH, Fuggerstrasse 11, D-86150 Augsburg, * Germany 2019
*
* This file is licensed under the Embedded Projects General Public License *Version 3.1. 
*
* You should have received a copy of this license from your vendor and/or *along with this file; If not, please visit www.wawision.de/Lizenzhinweis 
* to obtain the text of the corresponding license version.  
*
**** END OF COPYRIGHT & LICENSE NOTICE *** DO NOT REMOVE ****
*/
?>
<?php

use Xentral\Components\Http\JsonResponse;
use Xentral\Modules\Shopware6\Client\Shopware6Client;
use Xentral\Modules\Shopware6\Data\PriceData;

class Shopimporter_Shopware6 extends ShopimporterBase
{
    public $intern = false;
    public $shopid;
    public $data;
    public $UserName;
    public $Password;
    public $ShopUrl;
    public $createManufacturerAllowed;
    public $defaultManufacturer;
    public $defaultRuleName;
    public $statesToFetch;
    public $deliveryStatesToFetch;
    public $transactionStatesToFetch;
    public $salesChannelToFetch;
    public $orderSearchLimit;
    public $freeFieldOption;
    public $propertyOption;
    public $shopwareDefaultSalesChannel;
    public $shopwareMediaFolder;
    public $protocol;

    /** @var bool  */
    protected $exportCategories = false;
    /** @var Shopware6Client */
    protected $client;

    /**
     * @var Application
     */
    protected $app;
    protected $accessToken;
    /** @var array $currencyMapping available currency Iso Codes mapped to shopware IDs */
    protected $currencyMapping;
    /** @var array $knownShopLanguageIds */
    protected $knownShopLanguageIds = [];
    /** @var array $knownPropertyGroupIds */
    protected $knownPropertyGroupIds = [];
    /** @var array $knownManufacturerIds */
    protected $knownManufacturerIds = [];
    /** @var array $taxesInShop */
    protected $taxesInShop = [];


    /** @var bool $taxationByDestinationCountry */
    protected $taxationByDestinationCountry;

    /**
     * Shopimporter_Shopwaree6 constructor.
     *
     * @param      $app
     * @param bool $intern
     */
    public function __construct($app, $intern = false)
    {
        $this->app = $app;
        $this->intern = true;
        if ($intern) {
            return;
        }
        $this->app->ActionHandlerInit($this);

        $this->app->ActionHandler('list', 'Shopimporter_Shopware6List');
        $this->app->ActionHandler('auth', 'ImportAuth');
        $this->app->ActionHandler('sendlistlager', 'ImportSendListLager');
        $this->app->ActionHandler('getauftraegeanzahl', 'ImportGetAuftraegeAnzahl');
        $this->app->ActionHandler('getauftrag', 'ImportGetAuftrag');
        $this->app->ActionHandler('deleteauftrag', 'ImportDeleteAuftrag');
        $this->app->ActionHandler('updateauftrag', 'ImportUpdateAuftrag');
        $this->app->ActionHandler('storniereauftrag','ImportStorniereAuftrag');
        $this->app->ActionHandler('getarticle','ImportGetArticle');
        $this->app->ActionHandler('getarticlelist','ImportGetArticleList');
        $this->app->ActionHandler("updatezahlungsstatus","ImportUpdateZahlungsstatus");
        $this->app->DefaultActionHandler('list');

        $this->app->ActionHandlerListen($app);
    }

  /**
   * @param string $productId
   *
   * @return mixed
   */
    public function addSyncCustomFieldToProduct(string $productId)
    {
      $customField = [
        'customFields' => [
          'wawision_shopimporter_syncstate' => 1
        ]
      ];

      return $this->shopwareRequest('PATCH', "product/{$productId}", $customField);
    }

  /**
   * @param string $orderId
   *
   * @return mixed
   */
    public function addCustomFieldToOrder(string $orderId)
    {
      $customField = [
        'customFields' => [
          'wawision_shopimporter_syncstate' => 1
        ]
      ];

      return $this->shopwareRequest('PATCH', "order/{$orderId}", $customField);
    }

    public function ImportGetArticleList()
    {
        $page = 1;
        $limit = 500;

        do {
            $productIdsToAdd = [];
            $searchdata = [
                'limit' => $limit,
                'page' => $page,
                'filter' => [
                    [
                        'field' => 'product.parentId',
                        'type' => 'equals',
                        'value' => null
                    ]
                ]
            ];

            $productsInShop = $this->shopwareRequest('POST', 'search/product', $searchdata);
            if (!empty($productsInShop['data'])) {
                foreach ($productsInShop['data'] as $productInShop) {
                    $productIdsToAdd[] = $productInShop['id'];
                }
            }

            foreach ($productIdsToAdd as $productId) {
                $this->app->DB->Insert("INSERT INTO shopexport_getarticles (shop, nummer) VALUES ('$this->shopid', '" . $this->app->DB->real_escape_string($productId) . "')");
            }
            $page++;
        } while (count($productsInShop['data']) === $limit);


        $anzahl = $this->app->DB->Select("SELECT COUNT(id) FROM shopexport_getarticles WHERE shop=$this->shopid");
        $this->app->erp->SetKonfigurationValue('artikelimportanzahl_' . $this->shopid, $anzahl);

    }

    /**
     * @param string $method
     * @param string $endpoint
     * @param string $data
     *
     * @param array $headerInformation
     * @return mixed
     */
    public function shopwareRequest($method, $endpoint, $data = '', $headerInformation = [])
    {
        $accessToken = $this->shopwareToken();
        $url = $this->ShopUrl;
        $url .= $endpoint;

        $ch = curl_init();
        $headerInformation[] = 'Content-Type:application/json';
        $headerInformation[] = 'Authorization:Bearer ' . $accessToken['token'];
        curl_setopt($ch, CURLOPT_URL, $url);
        if (!empty($data)) {
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        }
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headerInformation);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $response = curl_exec($ch);
        if (curl_error($ch)) {
            $this->error[] = curl_error($ch);
        }
        curl_close($ch);

        return json_decode($response, true);
    }

    /**
     * @return array
     */
    protected function shopwareToken()
    {
        $result = [];

        $result['success'] = true;
        $result['token'] = $this->accessToken;
        $result['message'] = 'Keine Antwort von API erhalten.';

        if (!empty($result['token'])) {
            return $result;
        }

        $result['success'] = false;

        $data = [
            'username' => $this->UserName,
            'password' => $this->Password,
            'grant_type' => 'password',
            'scopes' => 'write',
            'client_id' => 'administration',
        ];

        $ch = curl_init($this->ShopUrl . 'oauth/token');
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
                'Accept: application/json',
                'Content-Type: application/json',
                'Cache-Control: no-cache',
            ]
        );
        $response = json_decode(curl_exec($ch), true);

        if (!empty((string)$response['title'])) {
            $result['message'] = $response['title'];
        }

        if (!empty($response['access_token'])) {
            $result['success'] = true;
            $this->accessToken = $response['access_token'];
            $result['token'] = $response['access_token'];
        }

        return $result;
    }

    public function ImportGetArticle()
    {
        $tmp = $this->CatchRemoteCommand('data');

        if (isset($tmp['nummerintern'])) {
            $nummer = $tmp['nummerintern'];
            $response = $this->shopwareRequest('GET', 'product/' . $nummer);
            if (empty($response['data'])) {
                $this->error[] = 'Artikel in der Shop Datenbank nicht gefunden!';
                return;
            }
            $nummer = $response['data']['attributes']['productNumber'];
        } else {
            $nummer = $tmp['nummer'];
        }
        $articleInfo = $this->shopwareRequest('GET', 'product?filter[product.productNumber]=' . $nummer .
            '&associations[manufacturer][]&associations[properties][]');
        if (empty($articleInfo['data'][0])) {
            $this->error[] = 'Artikel in der Shop Datenbank nicht gefunden!';
            return;
        }
        $articleIdInShop = $articleInfo['data'][0]['id'];
        if(empty($articleInfo['data'][0]['customFields'])
          || empty($articleInfo['data'][0]['customFields']['wawision_shopimporter_syncstate'])){
          $this->addSyncCustomFieldToProduct((string)$articleIdInShop);
        }

        $articleInfo = $this->shopwareRequest('GET', 'product?filter[product.productNumber]=' . $nummer .
        '&associations[manufacturer][]&associations[properties][]');
        $associatedInformation = [];
        $properties = [];
        foreach ($articleInfo['included'] as $includedInformation) {
            if ($includedInformation['type'] === 'property_group_option') {
                $properties[$includedInformation['id']] = $includedInformation['attributes'];
            } else {
                $associatedInformation[$includedInformation['id']] = $includedInformation['attributes'];
            }
        }
        $groups = [];
        if (!empty($properties)) {
            $groupsInShop = $this->shopwareRequest('GET', 'property-group');
            foreach ($groupsInShop['data'] as $groupInShop) {
                $groups[$groupInShop['id']] = $groupInShop['attributes']['name'];
            }
        }
        $media = $this->shopwareRequest('GET', 'product/' . $articleIdInShop . '/media');
        $imagesToAdd = [];
        if (!empty($media['included'])) {
            foreach ($media['included'] as $mediaInfo) {
                if ($mediaInfo['type'] === 'media') {
                    $imagesToAdd[] = [
                        'content' => base64_encode(@file_get_contents($mediaInfo['attributes']['url'])),
                        'path' => $mediaInfo['attributes']['url'],
                        'id' => $mediaInfo['id']
                    ];
                }
            }
        }
        $articleInfo = $articleInfo['data'][0]['attributes'];

        $data = [];
        $data['name'] = $articleInfo['name'];
        if (isset($tmp['nummerintern'])) {
            $data['nummer'] = $articleInfo['productNumber'];
        }


        $data['artikelnummerausshop'] = $articleInfo['productNumber'];
        $data['restmenge'] = $articleInfo['stock'];
        $data['uebersicht_de'] = $articleInfo['description'];
        $data['preis_netto'] = $articleInfo['price'][0]['net'];
        if (!empty($articleInfo['price'][0]['listPrice'])) {
            $data['pseudopreis'] = $articleInfo['price'][0]['listPrice'];
        }
        $data['aktiv'] = $articleInfo['active'];
        if (!empty($articleInfo['weight'])) {
            $data['gewicht'] = $articleInfo['weight'];
        }
        if (!empty($articleInfo['manufacturerNumber'])) {
            $data['herstellernummer'] = $articleInfo['manufacturerNumber'];
        }
        if (!empty($articleInfo['ean'])) {
            $data['ean'] = $articleInfo['ean'];
        }
        if (!empty($articleInfo['manufacturerId'])) {
            $data['hersteller'] = $associatedInformation[$articleInfo['manufacturerId']]['name'];
        }
        if (!empty($articleInfo['taxId'])) {
            $data['umsatzsteuer'] = $associatedInformation[$articleInfo['taxId']]['taxRate'];
        }
        if (!empty($properties)) {
            foreach ($properties as $property) {
                if ($this->propertyOption === 'toProperties') {
                    $data['eigenschaften'][] = [
                        'name' => $groups[$property['groupId']],
                        'values' => $property['name'],
                    ];
                }
                if ($this->propertyOption === 'toCustomFields') {
                    $data['freifeld_' . $groups[$property['groupId']]] = $property['name'];
                }
            }
        }
        if (!empty($articleInfo['customFields'])) {
            foreach ($articleInfo['customFields'] as $customFieldName => $customFieldValue) {
                if ($this->freeFieldOption === 'toProperties') {
                    $data['eigenschaften'][] = [
                        'name' => $customFieldName,
                        'values' => $customFieldValue
                    ];
                }
                if ($this->freeFieldOption === 'toCustomFields') {
                    $data['freifeld_' . $customFieldName] = $customFieldValue;
                }
            }
        }
        if (!empty($imagesToAdd)) {
            $data['bilder'] = $imagesToAdd;
        }


        if ($articleInfo['childCount'] > 0) {
            $data = [$data];

            $limit = 50;
            $page = 1;
            $optionInfo = [];
            $optionGroupInfo = [];
            do {

                $searchdata = [
                    'limit' => $limit,
                    'page' => $page,
                    'filter' => [
                        [
                            'field' => 'product.parentId',
                            'type' => 'equals',
                            'value' => $articleIdInShop
                        ]
                    ],
                    'sort' => [
                        [
                            'field' => 'product.options.groupId',
                            'naturalSorting' => false,
                            'order' => 'ASC'
                        ],
                        [
                            'field' => 'product.options.id',
                            'naturalSorting' => false,
                            'order' => 'ASC'
                        ]
                    ],
                    'associations' => [
                        'options' => [
                            'sort' => [
                                [
                                    'field' => 'groupId',
                                    'naturalSorting' => false,
                                    'order' => 'ASC'
                                ],
                                [
                                    'field' => 'id',
                                    'naturalSorting' => false,
                                    'order' => 'ASC'
                                ]
                            ]
                        ]
                    ]
                ];
                $variantsInShop = $this->shopwareRequest('POST', 'search/product', $searchdata);
                foreach ($variantsInShop['included'] as $includedInfo) {
                    if ($includedInfo['type'] === 'property_group_option') {
                        $optionInfo[$includedInfo['id']] = $includedInfo['attributes'];
                        if (empty($optionGroupInfo[$includedInfo['attributes']['groupId']])) {
                            $optionGroupInfo[$includedInfo['attributes']['groupId']] = (!empty($optionGroupInfo)?count($optionGroupInfo):0) + 1;
                        }
                    }
                }

                foreach ($variantsInShop['data'] as $variantInShop) {
                    $variantData = [];
                    $variantName = $data[0]['name'];
                    foreach ($variantInShop['attributes']['optionIds'] as $optionId) {
                        $variantData['matrixprodukt_wert' . $optionGroupInfo[$optionInfo[$optionId]['groupId']]] =
                            $optionInfo[$optionId]['name'];
                        $variantName .= ' - ' . $optionInfo[$optionId]['name'];
                    }

                    $variantData['name'] = $variantName;
                    $variantData['nummer'] = $variantInShop['attributes']['productNumber'];
                    $variantData['artikelnummerausshop'] = $variantInShop['attributes']['productNumber'];
                    $variantData['restmenge'] = $variantInShop['attributes']['stock'];
                    $variantData['uebersicht_de'] = $variantInShop['attributes']['description'];
                    if (empty($variantInShop['attributes']['price'][0]['net'])) {
                        $variantData['preis_netto'] = $data[0]['preis_netto'];
                    } else {
                        $variantData['preis_netto'] = $variantInShop['attributes']['price'][0]['net'];
                    }
                    if (!empty($variantInShop['attributes']['price'][0]['listPrice'])) {
                        $variantData['pseudopreis'] = $variantInShop['attributes']['price'][0]['listPrice'];
                    }
                    $variantData['aktiv'] = $variantInShop['attributes']['active'];
                    if (!empty($variantInShop['attributes']['weight'])) {
                        $variantData['gewicht'] = $variantInShop['attributes']['weight'];
                    }
                    if (!empty($variantInShop['attributes']['manufacturerNumber'])) {
                        $variantData['herstellernummer'] = $variantInShop['attributes']['manufacturerNumber'];
                    }
                    if (!empty($variantInShop['attributes']['ean'])) {
                        $variantData['ean'] = $variantInShop['attributes']['ean'];
                    }
                    if (!empty($data[0]['umsatzsteuer'])) {
                        $variantData['umsatzsteuer'] = $data[0]['umsatzsteuer'];
                    }

                    $data[] = $variantData;
                }

                $page++;
            } while (count($variantsInShop['data']) > $limit);

            foreach ($optionGroupInfo as $groupId => $sorting) {
                $data[0]['matrixprodukt_gruppe' . $sorting] = $groups[$groupId];
            }
            foreach ($optionInfo as $optionData) {
                $data[0]['matrixprodukt_optionen' . $optionGroupInfo[$optionData['groupId']]][] = $optionData['name'];
            }
        }

        //TODO Staffelpreise
        //TODO Kategorien
        //TODO Freifelder
        //TODO Crossselling

        return $data;
    }

    /**
     * @param array $data
     *
     * @return array
     */
    public function checkApiApp($data)
    {
        foreach (['shopwareUserName', 'shopwarePassword', 'shopwareUrl'] as $field) {
            if (empty($data['data'][$field])) {
                return ['success' => false, 'error' => sprintf('%s is empty', $field)];
            }
        }

        $shops = $this->app->DB->SelectArr(
            sprintf(
                "SELECT  `einstellungen_json`, `bezeichnung`,`id` 
          FROM `shopexport` 
          WHERE `modulename` = 'shopimporter_shopware6' 
            AND `einstellungen_json` IS NOT NULL AND `einstellungen_json` <> ''"
            )
        );
        if (empty($shops)) {
            return [
                'info' => [
                    'Shop' => 'Shopware',
                    'info' => 'Url ' . $data['data']['shopwareUrl'],
                ]
            ];
        }
        foreach ($shops as $shop) {
            if (empty($shop['einstellungen_json'])) {
                continue;
            }
            $json = @json_decode($shop['einstellungen_json'], true);
            if (empty($json['felder']) || empty($json['felder']['shopwareUrl'])) {
                continue;
            }
            if ($json['felder']['shopwareUrl'] === $data['data']['shopwareUrl']) {
                return [
                    'success' => false,
                    'error' => sprintf('Shop with url %s allready exists', $data['data']['shopwareUrl'])
                ];
            }
        }

        return [
            'info' => [
                'Shop' => 'Shopware',
                'info' => 'Url ' . $data['data']['shopwareUrl'],
            ]
        ];
    }

    /**
     *
     */
    public function Shopimporter_Shopware6List()
    {
        $msg = $this->app->erp->base64_url_encode('<div class="info">Sie k&ouml;nnen hier die Shops einstellen</div>');
        header('Location: index.php?module=onlineshops&action=list&msg=' . $msg);
        exit;
    }

    /**
     * @param $shopid
     * @param $data
     */
    public function getKonfig($shopid, $data)
    {
        $this->shopid = $shopid;
        $this->data = $data;
        $importerSettings = $this->app->DB->SelectArr("SELECT `einstellungen_json`, `kategorienuebertragen` FROM `shopexport` WHERE `id` = '$shopid' LIMIT 1");
        $importerSettings = reset($importerSettings);

        $this->exportCategories = (bool) $importerSettings['kategorienuebertragen'];

        $einstellungen = [];
        if (!empty($importerSettings['einstellungen_json'])) {
            $einstellungen = json_decode($importerSettings['einstellungen_json'], true);
        }
        $this->protocol = $einstellungen['felder']['protocol'];
        $this->UserName = $einstellungen['felder']['shopwareUserName'];
        $this->Password = $einstellungen['felder']['shopwarePassword'];
        $this->ShopUrl = rtrim($einstellungen['felder']['shopwareUrl'], '/') . '/';
        $this->createManufacturerAllowed = false;
        if ($einstellungen['felder']['shopwareAllowCreateManufacturer'] === '1') {
            $this->createManufacturerAllowed = true;
        }
        $this->defaultManufacturer = $einstellungen['felder']['shopwareDefaultManufacturer'];
        $this->defaultRuleName = $einstellungen['felder']['shopwareDefaultRuleName'];
        $this->statesToFetch = $einstellungen['felder']['statesToFetch'];
        $this->deliveryStatesToFetch = $einstellungen['felder']['deliveryStatesToFetch'];
        $this->transactionStatesToFetch = $einstellungen['felder']['transactionStatesToFetch'];
        $this->salesChannelToFetch = $einstellungen['felder']['salesChannelToFetch'];
        $this->orderSearchLimit = $einstellungen['felder']['orderSearchLimit'];
        $this->freeFieldOption = $einstellungen['felder']['shopwareFreeFieldOption'];
        $this->propertyOption = $einstellungen['felder']['shopwarePropertyOption'];
        $this->shopwareDefaultSalesChannel = $einstellungen['felder']['shopwareDefaultSalesChannel'];
        $this->shopwareMediaFolder = $einstellungen['felder']['shopwareMediaFolder'];
        $query = sprintf('SELECT `steuerfreilieferlandexport` FROM `shopexport`  WHERE `id` = %d', $this->shopid);
        $this->taxationByDestinationCountry = !empty($this->app->DB->Select($query));

      $this->client = $this->app->Container->get('Shopware6Client');
      $this->client->setCredentials(
        $this->UserName,
        $this->Password,
        $this->ShopUrl
      );
    }

    /**
     * @return array
     */
    public function EinstellungenStruktur()
    {
        return
            [
                'ausblenden' => ['abholmodus' => ['ab_nummer']],
                'functions' =>  ['exportartikelbaum','getarticlelist','updatezahlungsstatus'],
                'felder'     => [
                    'protocol'                        => [
                        'typ'         => 'checkbox',
                        'bezeichnung' => '{|Protokollierung im Logfile|}:',
                    ],
                    'shopwareUserName' => [
                        'typ' => 'text',
                        'bezeichnung' => '{|Benutzername|}:',
                        'size' => 40,
                    ],
                    'shopwarePassword' => [
                        'typ' => 'text',
                        'bezeichnung' => '{|Passwort|}:',
                        'size' => 40,
                    ],
                    'shopwareUrl' => [
                        'typ' => 'text',
                        'bezeichnung' => '{|Shop API URL|}:',
                        'size' => 40,
                    ],
                    'shopwareDefaultManufacturer' => [
                        'typ' => 'text',
                        'bezeichnung' => '{|Standard Hersteller|}:',
                        'size' => 40,
                        'default' => 'Keine Herstellerinformation',
                    ],
                    'shopwareAllowCreateManufacturer' => [
                        'typ' => 'checkbox',
                        'bezeichnung' => '{|Bei Artikelexport Hersteller anlegen|}:',
                    ],
                    'shopwareDefaultRuleName' => [
                        'typ' => 'text',
                        'bezeichnung' => '{|Name der Standardpreisgruppe|}:',
                        'size' => 40,
                        'default' => 'All customers',
                    ],
                    'shopwarePropertyOption' => [
                        'heading' => '{|Eigenschaften / Freifeld Zuordnung|}',
                        'typ' => 'select',
                        'bezeichnung' => '{|Xentral Artikel Eigenschaften|}:',
                        'size' => 40,
                        'default' => 'toProperties',
                        'optionen' => ['toProperties' => '{|Shopware Eigenschaften|}', 'toCustomFields' => '{|Shopware Zusatzfelder|}', 'doNotExport' => '{|Nicht übertragen|}']
                    ],
                    'shopwareFreeFieldOption' => [
                        'typ' => 'select',
                        'bezeichnung' => '{|Xentral Artikel Freifelder|}:',
                        'size' => 40,
                        'default' => 'toCustomFields',
                        'optionen' => ['toProperties' => '{|Shopware Eigenschaften|}', 'toCustomFields' => '{|Shopware Zusatzfelder|}', 'doNotExport' => '{|Nicht übertragen|}']
                    ],
                    'shopwareDefaultSalesChannel' => [
                        'heading' => '{|Artikelexport Standardeinstellungen|}',
                        'typ' => 'text',
                        'bezeichnung' => '{|Standard Sichtbarkeit|}:',
                        'size' => 40
                    ],
                        'shopwareMediaFolder' => [
                        'typ' => 'text',
                        'bezeichnung' => '{|Media Folder für Artikelbilder|}:',
                        'size' => 40,
                        'default' => 'Product Media'
                    ],
                    'statesToFetch' => [
                        'typ' => 'text',
                        'bezeichnung' => '{|Abzuholender Bestellstatus|}:',
                        'size' => 40,
                        'default' => 'open',
                        'col' => 2,
                        'info' => '<br />Erlaubte Werte: open;in_progress;completed;cancelled'
                    ],
                    'deliveryStatesToFetch' => [
                        'typ' => 'text',
                        'bezeichnung' => '{|Eingrenzen auf Lieferstatus|}:',
                        'size' => 40,
                        'default' => '',
                        'col' => 2,
                        'info' => '<br />Erlaubte Werte: open;shipped_partially;shipped;returned;returned_partially;cancelled'
                    ],
                    'transactionStatesToFetch' => [
                        'typ' => 'text',
                        'bezeichnung' => '{|Eingrenzen auf Bezahlstatus|}:',
                        'size' => 40,
                        'default' => '',
                        'col' => 2,
                        'info' => '<br />Erlaubte Werte: open;paid;authorized;paid_partially;refunded;refunded_partially;reminded;cancelled'
                    ],
                    'salesChannelToFetch' => [
                        'typ' => 'text',
                        'bezeichnung' => '{|Eingrenzen auf Sales Channel|}:',
                        'size' => 40,
                        'default' => '',
                        'col' => 2,
                        'info' => '<br />Klicke auf "Verbindung prüfen" um die verfügbaren Channels (bitte die Id verwenden) anzuzeigen.'
                    ],
                    'orderSearchLimit' => [
                        'typ' => 'select',
                        'bezeichnung' => '{|Anzahl Aufträge abholen|}:',
                        'optionen' => [
                            '25' => '25',
                            '50' => '50',
                            '75' => '75',
                            '100' => '100',
                        ],
                        'default' => '25',
                        'col' => 2
                    ],
                ],
            ];
    }

    public function ImportUpdateZahlungsstatus()
    {
        $tmp = $this->CatchRemoteCommand('data');
        $auftrag = $tmp['auftrag'];

        $transactions = $this->shopwareRequest('GET', 'order/'.$auftrag.'/transactions');
        $transactionId = $transactions['data'][0]['id'];

        if(empty($transactionId)){
            return;
        }

        $response = $this->shopwareRequest('POST', '_action/order_transaction/'.$transactionId.'/state/paid');
        if (!empty($response['id'])) {
            return 'ok';
        }
    }

  public function ImportSendArtikelbaum(){
    $xentralCategoryTree = [];
    $this->app->erp->GetKategorienbaum($xentralCategoryTree, 0, 0, $this->shopid);

        $xentralCategoryIdToParentId = [];
        foreach ($xentralCategoryTree as $key => $value) {
            $xentralCategoryTree[$key]['erledigt'] = false;
            $xentralCategoryTree[$key]['shopid'] = '';
            $xentralCategoryTree[$key]['aktiv'] = false;
            $xentralCategoryIdToParentId[$value['id']] = $key;
        }

        $parentCategoryId = null;
        foreach ($xentralCategoryTree as $index => $categoryData) {
            $this->createCategoryTree($index, $xentralCategoryTree, $xentralCategoryIdToParentId, $parentCategoryId);
        }
    }

    protected function createCategoryTree($id, &$xentralCategoryTree, $xentralCategoryIdToParentId, $parentCategoryId)
    {
        $parentId = $parentCategoryId;
        if ($xentralCategoryTree[$id]['parent']) {
            $parentId = $xentralCategoryTree[$xentralCategoryIdToParentId[$xentralCategoryTree[$id]['parent']]]['shopid'];
        }
        if ($xentralCategoryTree[$id]['parent'] && !$xentralCategoryTree[$xentralCategoryIdToParentId[$xentralCategoryTree[$id]['parent']]]['erledigt']) {
            $this->createCategoryTree($xentralCategoryIdToParentId[$xentralCategoryTree[$id]['parent']], $xentralCategoryTree, $xentralCategoryIdToParentId, $parentCategoryId);
        }
        $xentralCategoryTree[$id]['erledigt'] = true;

        $categoryName = $xentralCategoryTree[$id]['bezeichnung'];
        $searchdata = [
            'limit' => 25,
            'filter' => [
                [
                    'field' => 'category.name',
                    'type' => 'equals',
                    'value' => $categoryName
                ],
                [
                    'field' => 'category.parentId',
                    'type' => 'equals',
                    'value' => $parentId
                ]
            ]
        ];

        $categoriesInShop = $this->shopwareRequest('POST', 'search/category', $searchdata);

        $categoryId = '';
        if (!empty($categoriesInShop['data'])) {
            $categoryId = $categoriesInShop['data'][0]['id'];
        }

        if (!$categoryId) {
            $categoryData = [
                'parentId' => $parentId,
                'name' => $categoryName
            ];
            $result = $this->shopwareRequest('POST', 'category?_response=true', $categoryData);
            if ($result['data']['id']) {
                $categoryId = $result['data']['id'];
            }
        }

        if ($categoryId) {
            $xentralCategoryTree[$id]['shopid'] = $categoryId;
        }
    }

    /**
     * @return int
     */
    public function ImportSendListLager()
    {
        $tmp = $this->CatchRemoteCommand('data');

        $count = 0;
        foreach ($tmp as $article) {
            $artikel = $article['artikel'];
            if ($artikel === 'ignore') {
                continue;
            }
            $nummer = $article['nummer'];
            $fremdnummer = $article['fremdnummer'];
            if (!empty($fremdnummer)) {
                $nummer = $fremdnummer;
            }
            $articleInfo = $this->shopwareRequest('GET', 'product?filter[product.productNumber]=' . $nummer);

            if (empty($articleInfo['data'][0]['id'])) {
                $this->Shopware6Log('Artikel wurde nicht im Shop gefunden: ' . $nummer, $articleInfo);
                continue;
            }
            if(empty($articleInfo['data'][0]['customFields'])
              || empty($articleInfo['data'][0]['customFields']['wawision_shopimporter_syncstate'])){
              $this->addSyncCustomFieldToProduct((string)$articleInfo['data'][0]['id']);
            }

            $active = true;
            if ($article['inaktiv']) {
                $active = false;
            }

            $stock = $article['anzahl_lager'];
            if (!empty($article['pseudolager'])) {
                $stock = $article['pseudolager'];
            }
            $stock = $this->getCorrectedStockFromAvailable($active, (int)$stock, $articleInfo);
            $data = [
                'stock' => $stock,
                'active' => $active,
            ];
            $response = $this->shopwareRequest('PATCH', 'product/' . $articleInfo['data'][0]['id'], $data);
            $this->Shopware6Log('Lagerbestand konnte nicht uebertragen werden fuer Artikel: ' . $nummer, $response);
            $count++;
        }

        return $count;
    }

  /**
   * @param bool       $isStockActive
   * @param int        $stock
   * @param array|null $articleInfo
   *
   * @return int
   */
    public function getCorrectedStockFromAvailable(bool $isStockActive, int $stock, ?array $articleInfo): int
    {
      if(!$isStockActive) {
        return $stock;
      }
      if(empty($articleInfo)) {
        return $stock;
      }
      if(!isset($articleInfo['data'][0]['attributes']['availableStock'])) {
        return $stock;
      }
      if(!isset($articleInfo['data'][0]['attributes']['availableStock'])) {
        return $stock;
      }
      $reserved = (int)$articleInfo['data'][0]['attributes']['stock']
        - (int)$articleInfo['data'][0]['attributes']['availableStock'];
      if($reserved <= 0) {
        return $stock;
      }

      return $stock + $reserved;
    }

    /**
     * @param string $message
     * @param mixed $dump
     */
    public function Shopware6Log($message, $dump = '')
    {
        if ($this->protocol) {
            $this->app->erp->Logfile($message, print_r($dump, true));
        }
    }

    /**
     * @return int
     */
    public function ImportSendList()
    {
        $articleList = $this->CatchRemoteCommand('data');

        $successCounter = 0;
        foreach ($articleList as $article) {
            $number = $article['nummer'];
            $articleInfo = $this->shopwareRequest(
                'GET',
                sprintf('product?filter[product.productNumber]=%s', $number)
            );
            $articleIdShopware = '';
            if (!empty($articleInfo['data'][0]['id'])) {
                $articleIdShopware = $articleInfo['data'][0]['id'];
            }

            $quantity = $article['anzahl_lager'];
            if (!empty($article['pseudolager'])) {
                $quantity = $article['pseudolager'];
            }
            $inaktiv = $article['inaktiv'];
            $active = true;
            if (!empty($inaktiv)) {
                $active = false;
            }
            $quantity = $this->getCorrectedStockFromAvailable($active, (int)$quantity, $articleInfo);
            $taxRate = (float)$article['steuersatz'];

            $taxId = $this->getTaxIdByRate($taxRate);

            $mediaToAdd = $this->mediaToExport($article, $articleIdShopware);

            $categoriesToAdd = [];
            if($this->exportCategories){
              $categoriesToAdd = $this->categoriesToExport($article, $articleIdShopware);
            }

            $propertiesToAdd = $this->propertiesToExport($article, $articleIdShopware);

            $crosselingToAdd = $this->crosssellingToExport($article, $articleIdShopware);

            $systemFieldsToAdd = $this->systemFieldsToExport($article, $articleIdShopware);

            $deliveryTimeId = null;
            if(!empty($article['lieferzeitmanuell'])){
              $deliveryTimeId = $this->getDeliveryTimeId($article['lieferzeitmanuell']);
            }

            if (empty($systemFieldsToAdd['visibilities']) && !empty($this->shopwareDefaultSalesChannel)) {
                $systemFieldsToAdd['visibilities'] = $this->modifySalesChannel(explode(',', $this->shopwareDefaultSalesChannel), $articleIdShopware);
            }

            if(empty($systemFieldsToAdd['unitId']) && !empty($article['einheit']) ){
                $systemFieldsToAdd['unitId'] = $this->unitToAdd($article['einheit']);
            }


            //Hersteller in Shopware suchen bzw. Anlegen
            $manufacturerName = $article['hersteller'];
            $manufacturerId = $this->getManufacturerIdByName($manufacturerName);

            if ($manufacturerId === null && $this->createManufacturerAllowed === true) {
                $manufacturerId = $this->createManufacturer($manufacturerName);
            }

            if (empty($manufacturerId)) {
                return 'error: Für den Artikelexport ist die Herstellerinformation zwingend erforderlich';
            }

            $isCloseOut = false;
            if(!empty($article['restmenge'])){
                $isCloseOut = true;
            }

            $description = $this->prepareDescription($article['uebersicht_de']);
            $ean = $article['ean'];
            $metaTitle = $article['metatitle_de'];
            $metaDescription = $article['metadescription_de'];
            $metaKeywords = $article['metakeywords_de'];

            $manufacturerNumber = $article['herstellernummer'];
            if (empty($manufacturerNumber)) {
                $manufacturerNumber = '';
            }

            $weight = (float)$article['gewicht'];
            $length = (float)$article['laenge'] * 10;
            $height = (float)$article['hoehe'] * 10;
            $width = (float)$article['breite'] * 10;

            $purchasePrice = (float)$article['einkaufspreis'];

            $currencyId = $this->findCurrencyId($article['waehrung']);
            $price = [
                'net' => $article['preis'],
                'gross' => $article['bruttopreis'],
                'currencyId' => $currencyId,
                'linked' => true];

            if (!empty($article['pseudopreis'])) {
                $price['listPrice'] = [
                    'currencyId' => $currencyId,
                    'gross' => $article['pseudopreis'],
                    'linked' => true,
                    'net' => $article['pseudopreis']/(1+$taxRate/100)
                ];
            }

            $data = [
                'name' => $article['name_de'],
                'isCloseout' => $isCloseOut,
                'productNumber' => $number,
                'manufacturerId' => $manufacturerId,
                'stock' => (int)$quantity,
                'taxId' => $taxId,
                'active' => $active,
                'description' => $description,
                'ean' => $ean,
                'metaTitle' => $metaTitle,
                'metaDescription' => $metaDescription,
                'keywords' => $metaKeywords,
                'manufacturerNumber' => $manufacturerNumber,
                'length' => $length,
                'width' => $width,
                'height' => $height,
                'weight' => $weight,
                'purchasePrice' => $purchasePrice,
                'price' => [$price],
                'categories' => $categoriesToAdd,
                'properties' => $propertiesToAdd,
                'crossSellings' => $crosselingToAdd,
                'media' => $mediaToAdd,
                'deliveryTimeId' => $deliveryTimeId
            ];

            $data = array_merge($data, $systemFieldsToAdd);
            if(empty($data['customFields'])
              || empty($data['customFields']['wawision_shopimporter_syncstate'])){
              $data['customFields']['wawision_shopimporter_syncstate'] = 1;
            }

            if (empty($articleIdShopware)) {
                $result = $this->shopwareRequest('POST',
                    'product?_response=true', $data);
                if (!empty($result['data']['id'])) {
                    $articleIdShopware = $result['data']['id'];
                    $articleInfo['data'][0] = $result['data'];
                }
            } else {
                $headerInformation = [];
                $languageId = $this->getLanguageIdByCountryIso('DE');
                if (!empty($languageId)) {
                    $headerInformation[] = 'sw-language-id: ' . $languageId;
                }
                $result = $this->shopwareRequest('PATCH',
                    sprintf('product/%s?_response=true', $articleIdShopware), $data, $headerInformation);
            }

            if(!empty($articleIdShopware)){
                $this->exportTranslationsForArticle($article, $articleIdShopware);
            }

            $this->addCoverImage($article, $articleIdShopware);

            if (empty($result['data']) || is_array($result['errors'])) {
                $this->Shopware6Log('Artikelexport fehlgeschlagen', ['data:' => $data, 'response' => $result]);
                continue;
            }

            $this->exportSeoUrls($article, $articleIdShopware);

            $this->exportVariants($article, $articleIdShopware, $currencyId);

            if (empty($result['data']) || is_array($result['errors'])) {
                $this->Shopware6Log('Artikelexport bei Bild&uuml;bertragung fehlgeschlagen', ['data:' => $data, 'response' => $result]);
                continue;
            }

          $defaultPrices = $this->getPricesFromArray($article['staffelpreise_standard'] ?? []);
          $groupPrices = $this->getPricesFromArray($article['staffelpreise_gruppen'] ?? []);

          if (!empty($defaultPrices) || !empty($groupPrices)) {
            $this->deleteOldBulkPrices($articleIdShopware);
          }
          if (!empty($defaultPrices)) {
            foreach ($defaultPrices as $priceData) {
              $this->exportBulkPriceForGroup($articleIdShopware, $this->defaultRuleName, $priceData);
            }
          }
          if (!empty($groupPrices)) {
            foreach ($groupPrices as $priceData) {
              $this->exportBulkPriceForGroup($articleIdShopware, $priceData->getGroupName(), $priceData);
            }
          }

          $successCounter++;
        }

        return $successCounter;
    }

  protected function exportBulkPriceForGroup(string $productId, string $groupName, PriceData $priceData): void
  {
    $currencyId = $this->findCurrencyId($priceData->getCurrency());

    $groupRuleId = $this->client->getGroupRuleId($groupName);
    if (empty($groupRuleId)) {
      $this->Shopware6Log("Fehler: Gruppe {$groupName} konnte im Shop nicht gefunden werden");
      return;
    }

    $result = $this->client->saveBulkPrice($productId, $groupRuleId, $currencyId, $priceData);
    if (empty($result['data'])) {
        $this->Shopware6Log("Fehler: Staffelpreis für Gruppe {$groupName} konnte nicht exportiert werden", $result);
    }
  }

  /**
   * @param string $deliveryTimeText
   *
   * @return string|null
   */
  protected function getDeliveryTimeId(string $deliveryTimeText): ?string
  {
    $searchCommand = [
      'limit' => 5,
      'filter' => [
        [
          'field' => 'name',
          'type' => 'equals',
          'value' => $deliveryTimeText
        ]
      ]
    ];
    $result = $this->shopwareRequest('POST', 'search/delivery-time', $searchCommand);

    if (empty($result['data'][0]['id'])) {
      return null;
    }

    return $result['data'][0]['id'];
  }

  /**
     * @param string $description
     * @return string
     */
    protected function prepareDescription($description): string
    {
        $markupSubstitute = [
            '/&quot;/' => '"',
            '/&lt;([^&]+)&gt;/' => '<\1>',
            '/\\<strong>/' => '<b>',
            '/\\<\/strong>/' => '</b>',
            '/\\<em>/' => '<i>',
            '/\\<\/em>/' => '</i>',
            '/&amp;/' => '&',
        ];

        return (string)preg_replace(array_keys($markupSubstitute), array_values($markupSubstitute), $description);
    }

    /**
     * @param array $article
     * @param string $articleIdShopware
     */
    protected function exportTranslationsForArticle(array $article, string $articleIdShopware): void
    {
        $customFieldsToAdd = $this->customFieldsToExport($article, $articleIdShopware);

        $preparedTranslations = [];
        $preparedTranslations['DE'] = [
            'name' => $article['name_de'],
            'description' => $this->prepareDescription($article['uebersicht_de']),
            'metaTitle' => $article['metatitle_de'],
            'metaDescription' => $article['metadescription_de'],
            'keywords' => $article['metakeywords_de'],
            'customFields' => []
        ];
        if(!empty($customFieldsToAdd['DE'])){
            $preparedTranslations['DE']['customFields'] = $customFieldsToAdd['DE'];
        }
        $preparedTranslations['GB'] = [
            'name' => $article['name_en'],
            'description' => $this->prepareDescription($article['uebersicht_en']),
            'metaTitle' => $article['metatitle_en'],
            'metaDescription' => $article['metadescription_en'],
            'keywords' => $article['metakeywords_en'],
            'customFields' => [],
        ];
        if(!empty($customFieldsToAdd['GB'])){
            $preparedTranslations['GB']['customFields'] = $customFieldsToAdd['GB'];
        }
        foreach ($article['texte'] as $translation) {
            if ($translation['sprache'] === 'EN') {
                $translation['sprache'] = 'GB';
            }
            $preparedTranslations[$translation['sprache']] = [
                'name' => $translation['name'],
                'description' => $this->prepareDescription($translation['beschreibung_online']),
                'metaTitle' => $translation['meta_title'],
                'metaDescription' => $translation['meta_description'],
                'keywords' => $translation['meta_keywords'],
            ];
            if(!empty($customFieldsToAdd[$translation['sprache']])){
                $preparedTranslations[$translation['sprache']]['customFields'] = $customFieldsToAdd[$translation['sprache']];
            }
        }

        foreach ($preparedTranslations as $countryIsoCode => $translation) {
            $languageId = $this->getLanguageIdByCountryIso($countryIsoCode);
            if (empty($languageId)) {
                $this->Shopware6Log('Language Id not found for country: ' . $countryIsoCode);
                continue;
            }

            $headerInformation = ['sw-language-id: ' . $languageId];
            $this->shopwareRequest(
                'PATCH',
                sprintf('product/%s', $articleIdShopware),
                $translation, $headerInformation
            );
        }
    }

    /**
     * @param string $countryIso
     *
     * @return string|null
     */
    protected function getLanguageIdByCountryIso(string $countryIso): ?string
    {
        if(array_key_exists($countryIso, $this->knownShopLanguageIds)){
            return $this->knownShopLanguageIds[$countryIso];
        }

        $searchCommand = [
            'limit' => 5,
            'filter' => [
                [
                    'field' => 'country.iso',
                    'type' => 'equals',
                    'value' => $countryIso
                ]
            ]
        ];
        $countryInformation = $this->shopwareRequest('POST', 'search/country', $searchCommand);

        foreach ($countryInformation['data'] as $country){
            $searchCommand = [
                'limit' => 5,
                'filter' => [
                    [
                        'field' => 'locale.territory',
                        'type' => 'equals',
                        'value' => $country['attributes']['name']
                    ]
                ]
            ];
            $localeInformation = $this->shopwareRequest('POST', 'search/locale', $searchCommand);
            foreach ($localeInformation['data'] as $locale) {
                $searchCommand = [
                    'limit' => 5,
                    'filter' => [
                        [
                            'field' => 'language.localeId',
                            'type' => 'equals',
                            'value' => $locale['id']
                        ]
                    ]
                ];
                $languageInformation = $this->shopwareRequest('POST', 'search/language', $searchCommand);
                if (!empty($languageInformation['data'][0]['id'])) {
                    $this->knownShopLanguageIds[$countryIso] = $languageInformation['data'][0]['id'];
                    return $languageInformation['data'][0]['id'];
                }
            }
        }
        $this->knownShopLanguageIds[$countryIso] = null;

        return null;
    }

    /**
     * @param string $manufacturerName
     *
     * @return null|string
     */
    protected function createManufacturer(string $manufacturerName): ?string
    {
        $data = ['name' => $manufacturerName];
        $response = $this->shopwareRequest('POST', 'product-manufacturer?_response=true', $data);

        $manufacturerId = null;
        if(!empty($response['data']['id'])){
            $manufacturerId = $response['data']['id'];
            $this->knownManufacturerIds[$manufacturerName] = $manufacturerId;
        }

        return $manufacturerId;
    }

    /**
     * @param string $manufacturerName
     *
     * @return null|string
     */
    protected function getManufacturerIdByName(string $manufacturerName): ?string
    {
        if (!empty($this->knownManufacturerIds[$manufacturerName])) {
            return $this->knownManufacturerIds[$manufacturerName];
        }

        $manufacturerId = null;
        if (empty($manufacturerName)) {
            $manufacturerName = $this->defaultManufacturer;
        }
        $manufacturer = $this->shopwareRequest(
            'GET',
            'product-manufacturer?filter[product_manufacturer.name]=' . urlencode($manufacturerName)
        );
        $manufacturerId = $manufacturer['data'][0]['id'];
        $this->knownManufacturerIds[$manufacturerName] = $manufacturerId;

        return $manufacturerId;
    }

    /**
     * @param float $taxRate
     *
     * @return string
     */
    protected function getTaxIdByRate(float $taxRate): string{
        if(empty($this->taxesInShop)){
            $this->taxesInShop = $this->shopwareRequest('GET', 'tax');
        }
        foreach ($this->taxesInShop['data'] as $taxData) {
            if (abs(($taxData['attributes']['taxRate']-$taxRate)) < 0.0001 ) {
                return $taxData['id'];
            }
        }

        return $this->taxesInShop['data'][0]['id'];
    }

    /**
     * @param array $internalArticleData
     * @param string $articleIdShopware
     *
     * @return array
     */
    protected function mediaToExport($internalArticleData, $articleIdShopware)
    {
        $mediaToAdd = [
        ];

        if (empty($internalArticleData['Dateien'])) {
            return $mediaToAdd;
        }
        $internalMediaIds = [];

        $searchdata = [
            'limit' => 1,
            'filter' => [
                [
                    'field' => 'name',
                    'type' => 'equals',
                    'value' => $this->shopwareMediaFolder
                ]
            ]
        ];
        $mediaFolderData = $this->shopwareRequest('POST', 'search/media-folder', $searchdata);
        if(empty($mediaFolderData['data'][0]['id'])){
          $this->Shopware6ErrorLog('Kein Media Folder gefunden für: ', $this->shopwareMediaFolder);
          return [];
        }

        $mediaFolderId = $mediaFolderData['data'][0]['id'];

        foreach ($internalArticleData['Dateien'] as $internalFile) {
            $filename = explode('.', $internalFile['filename']);
            unset($filename[(!empty($filename)?count($filename):0) - 1]);
            $filename = $internalFile['id'].'_'.implode($filename);
            $extension = $internalFile['extension'];
            $imageTitle = (string)$internalFile['titel'];
            $imageAltText = (string)$internalFile['beschreibung'];
            $accessToken = $this->shopwareToken();

            $searchdata = [
                'limit' => 5,
                'filter' => [
                    [
                        'field' => 'media.fileName',
                        'type' => 'equals',
                        'value' => $filename
                    ]
                ]
            ];
            $mediaData = $this->shopwareRequest('POST', 'search/media', $searchdata);
            if (!empty($mediaData['data'][0]['id'])) {
                $internalMediaIds[] = $mediaData['data'][0]['id'];
                if($mediaData['data'][0]['attributes']['title'] !== $imageTitle
                  || $mediaData['data'][0]['attributes']['alt'] !== $imageAltText){
                  $this->setMediaTitleAndAltText($mediaData['data'][0]['id'], $imageTitle, $imageAltText);
                }
                continue;
            }

            $mediaData = $this->shopwareRequest('POST', 'media?_response=true', []);
            if(empty($mediaData['data']['id'])){
              $this->Shopware6Log('Error when creating media for sku: ' . $internalArticleData['nummer'],
                ['mediaData' => $mediaData, 'title' => $imageTitle, 'text' => $imageAltText]);
              continue;
            }
            $mediaId = $mediaData['data']['id'];
            $this->setMediaTitleAndAltText($mediaId, $imageTitle, $imageAltText);

            $mediaAssociationData = [
                [
                    'action' => 'upsert',
                    'entity' => 'media',
                    'payload' => [
                        [
                            'id' => $mediaId,
                            'mediaFolderId' => $mediaFolderId
                        ]
                    ]
                ]
            ];
            $this->shopwareRequest('POST', '_action/sync?_response=true', $mediaAssociationData);

            $url = $this->ShopUrl . '_action/media/' . $mediaId . '/upload?extension=' . $extension . '&fileName=' . $filename;
            $ch = curl_init();
            $setHeaders = [
                'Content-Type:image/' . $extension,
                'Authorization:Bearer ' . $accessToken['token']
            ];
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_POSTFIELDS, base64_decode($internalFile['datei']));
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
            curl_setopt($ch, CURLOPT_HTTPHEADER, $setHeaders);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_exec($ch);

            $internalMediaIds[] = $mediaId;
        }

        $existingMediaConnection = [];
        if (!empty($articleIdShopware)) {
            $existingMediaConnection = $this->shopwareRequest('GET', 'product/' . $articleIdShopware . '/media?limit=100');
            foreach ($existingMediaConnection['data'] as $existingConnection) {
                if (!in_array($existingConnection['attributes']['mediaId'], $internalMediaIds, false)) {
                    $this->shopwareRequest('DELETE', 'product/' . $articleIdShopware . '/media/' . $existingConnection['id']);
                }
            }
        }

        $alreadyAddedMediaIDs = [];
        if (!empty($existingMediaConnection)) {
            foreach ($existingMediaConnection['data'] as $existingConnection) {
                $alreadyAddedMediaIDs[$existingConnection['attributes']['mediaId']] = $existingConnection['id'];
            }
        }
        $position = 0;
        foreach ($internalMediaIds as $mediaId) {
            $mediaDataSet = [
                'mediaId' => $mediaId,
                'position' => $position
            ];
            if (array_key_exists($mediaId, $alreadyAddedMediaIDs)) {
                $mediaDataSet['id'] = $alreadyAddedMediaIDs[$mediaId];
            }
            $mediaToAdd[] = $mediaDataSet;
            $position++;
        }

        return $mediaToAdd;
    }

  /**
   * @param string $mediaId
   * @param string $title
   * @param string $altText
   */
  protected function setMediaTitleAndAltText(string $mediaId, string $title, string $altText): void
  {
    $this->shopwareRequest('PATCH', 'media/' . $mediaId,
      ['title' => $title,
        'alt' => $altText
      ]
    );
  }

    /**
     * @param array $articleInXentral
     * @param string $articleIdShopware
     */
    protected function addCoverImage($articleInXentral, $articleIdShopware){
        if(empty($articleIdShopware)){
            return;
        }
        if(empty($articleInXentral['Dateien'])){
            return;
        }
        $existingMediaConnection = $this->shopwareRequest('GET', 'product/' . $articleIdShopware . '/media?limit=100');
        if(empty($existingMediaConnection['data'])){
            return;
        }
        foreach ($articleInXentral['Dateien'] as $xentralFile) {
            $filename = explode('.', $xentralFile['filename']);
            unset($filename[(!empty($filename)?count($filename):0) - 1]);
            $filename = $xentralFile['id'].'_'.implode($filename);

            $searchdata = [
                'limit' => 5,
                'filter' => [
                    [
                        'field' => 'media.fileName',
                        'type' => 'equals',
                        'value' => $filename
                    ]
                ]
            ];
            $mediaData = $this->shopwareRequest('POST', 'search/media', $searchdata);
            $mediaId = $mediaData['data'][0]['id'];

            foreach ($existingMediaConnection['data'] as $mediaConnection){
                if($mediaId === $mediaConnection['attributes']['mediaId']){

                    $this->shopwareRequest('PATCH',
                        sprintf('product/%s?_response=true', $articleIdShopware),['coverId' => $mediaConnection['id']]);
                    return;
                }
            }
        }
    }

    /**
     * @param array $articleInXentral
     * @param string $articleIdShopware
     * @return array
     */
    protected function categoriesToExport($articleInXentral, $articleIdShopware)
    {
        $categoryName = $articleInXentral['kategoriename'];
        $categoryTree = $articleInXentral['kategorien'];

        $categoriesToAdd = [];
        if (empty($categoryName) && empty($categoryTree)) {
            return $categoriesToAdd;
        }

        $categoriesInXentral = [];
        if (!empty($categoryTree)) {
            $rootcategory = null;
            $categoryTreeid = [];
            foreach ($categoryTree as $categoryData) {
                $categoryData['shopwareparent'] = 0;
                if (!$categoryData['parent']) {
                    $categoryData['shopwareid'] = $rootcategory;
                }
                $categoryTreeid[$categoryData['id']] = $categoryData;
            }

            foreach ($categoryTree as $categoryData) {
                $parentid = $rootcategory;
                if (!empty($categoryData['parent'])) {
                    $parentid = $this->getCategoryParentId($categoryData, $categoryTreeid);
                }

                $searchdata = [
                    'limit' => 25,
                    'filter' => [
                        [
                            'field' => 'category.name',
                            'type' => 'equals',
                            'value' => $categoryData['name']
                        ]
                    ]
                ];
                if (!empty($parentid)) {
                    $searchdata['filter'][] = [
                        'field' => 'category.parentId',
                        'type' => 'equals',
                        'value' => $parentid
                    ];
                }
                $result = $this->shopwareRequest('POST', 'search/category', $searchdata);


                if (!empty($result['data'][0]['id'])) {
                    $categoryTreeid[$categoryData['id']]['shopwareid'] = $result['data'][0]['id'];
                    $categoriesInXentral[] = $result['data'][0]['id'];
                }
            }
        } else if (!empty($categoryName)) {
            $searchdata = [
                'limit' => 25,
                'filter' => [
                    [
                        'field' => 'category.name',
                        'type' => 'equals',
                        'value' => $categoryName
                    ]
                ]
            ];

            $result = $this->shopwareRequest('POST', 'search/category', $searchdata);

            if (!empty($result['data'][0]['id'])) {
                $categoriesInXentral[] = $result['data'][0]['id'];
            }
        }

        if (!empty($articleIdShopware)) {
            $existingCategories = $this->shopwareRequest('GET', 'product/' . $articleIdShopware . '/categories?limit=50');
            foreach ($existingCategories['data'] as $existingCategory) {
                if (!in_array($existingCategory['id'], $categoriesInXentral, false)) {
                    $this->shopwareRequest('DELETE', 'product/' . $articleIdShopware . '/categories/' . $existingCategory['id']);
                }
            }
        }
        foreach ($categoriesInXentral as $categoryId) {
            $categoriesToAdd[] = ['id' => $categoryId];
        }


        return $categoriesToAdd;
    }

    /**
     * @param $categoryData
     * @param $categoryTreeId
     * @return string|null
     */
    protected function getCategoryParentId($categoryData, &$categoryTreeId)
    {
        $parentId = $categoryTreeId[$categoryData['parent']]['shopwareid'];
        if (!empty($parentId)) {
            return $parentId;
        }

        $parentCategoryData = $this->app->DB->SelectRow("SELECT id,parent,bezeichnung AS name FROM artikelkategorien WHERE id<>'' AND id<>'0' AND id='" . $categoryData['parent'] . "' LIMIT 1");
        if (empty($parentCategoryData)) {
            return null;
        }

        $searchData = [
            'limit' => 25,
            'filter' => [
                [
                    'field' => 'category.name',
                    'type' => 'equals',
                    'value' => $parentCategoryData['name']
                ]
            ]
        ];
        $result = $this->shopwareRequest('POST', 'search/category', $searchData);

        if (count($result['data']) < 1) {
            return null;
        }

        if (count($result['data']) === 1) {
            $parentCategoryData['shopwareid'] = $result['data'][0]['id'];
            $categoryTreeId[$parentCategoryData['id']] = $parentCategoryData;
            return $result['data'][0]['id'];
        }

        $grandparentId = $this->getCategoryParentId($parentCategoryData, $categoryTreeId);

        $searchData = [
            'limit' => 25,
            'filter' => [
                [
                    'field' => 'category.name',
                    'type' => 'equals',
                    'value' => $parentCategoryData['name']
                ],
                [
                    'field' => 'category.parentId',
                    'type' => 'equals',
                    'value' => $grandparentId
                ]
            ]
        ];
        $result = $this->shopwareRequest('POST', 'search/category', $searchData);


        if (count($result['data']) === 1) {
            $parentCategoryData['shopwareid'] = $result['data'][0]['id'];
            $categoryTreeId[$parentCategoryData['id']] = $parentCategoryData;
            return $result['data'][0]['id'];
        }
        return null;
    }

    /**
     * @param string $propertyName
     *
     * @return string|null
     */
    protected function getPropertyGroupId($propertyName): ?string
    {
        if(array_key_exists($propertyName, $this->knownPropertyGroupIds)){
            return $this->knownPropertyGroupIds[$propertyName];
        }

        $searchData = [
            'limit' => 25,
            'filter' => [
                [
                    'field' => 'property_group.name',
                    'type' => 'equals',
                    'value' => $propertyName
                ]
            ]
        ];

        $germanLanguageId = $this->getLanguageIdByCountryIso('DE');
        $headerInformation = ['sw-language-id: ' . $germanLanguageId];
        $propertyData = $this->shopwareRequest(
            'POST',
            'search/property-group',
            $searchData,
            $headerInformation);
        if (empty($propertyData['data'][0]['id'])) {
            return null;
        }

        $this->knownPropertyGroupIds[$propertyName] = $propertyData['data'][0]['id'];

        return $propertyData['data'][0]['id'];
    }

    /**
     * @param string $propertyName
     * @return null|string
     */
    protected function createPropertyGroup($propertyName): ?string
    {
        $propertyGroupData = [
            'displayType' => 'text',
            'name' => $propertyName,
            'sortingType' => 'alphanumeric'
        ];
        $propertyGroup = $this->shopwareRequest(
            'POST',
            'property-group?_response=true',
            $propertyGroupData);

        $this->knownPropertyGroupIds[$propertyName] = $propertyGroup['data']['id'];

        if (empty($propertyGroup['data']['id'])) {
            return null;
        }

        return $propertyGroup['data']['id'];
    }

    /**
     * @param string $propertyGroupId
     * @param string $propertyName
     * @param string $countryIsoCode
     */
    protected function createTranslationForPropertyGroup($propertyGroupId, $propertyName, $countryIsoCode): void
    {
        $languageId = $this->getLanguageIdByCountryIso($countryIsoCode);
        if (empty($languageId)) {
            return;
        }

        $headerInformation = ['sw-language-id: ' . $languageId];

        $translation = [
            'name' => $propertyName,
        ];

        $this->shopwareRequest(
            'PATCH',
            sprintf('property-group/%s', $propertyGroupId),
            $translation,
            $headerInformation);
    }

    /**
     * @param string $propertyGroupId
     * @param string $propertyOptionName
     * @param string $countryIsoCode
     * @return mixed|null
     */
    protected function getPropertyOptionId($propertyGroupId, $propertyOptionName, $countryIsoCode = 'DE'): ?string
    {
        $searchData = [
            'limit' => 25,
            'filter' => [
                [
                    'field' => 'property_group_option.name',
                    'type' => 'equals',
                    'value' => $propertyOptionName
                ]
            ]
        ];
        $languageId = $this->getLanguageIdByCountryIso($countryIsoCode);
        $headerInformation = ['sw-language-id: ' . $languageId];
        $optionData = $this->shopwareRequest(
            'POST',
            'search/property-group/' . $propertyGroupId . '/options',
            $searchData,
            $headerInformation);

        if (empty($optionData['data'][0]['id'])) {
            return null;
        }

        return $optionData['data'][0]['id'];
    }

    /**
     * @param string $propertyGroupId
     * @param string $propertyOptionName
     * @return null|string
     */
    protected function createPropertyOption($propertyGroupId, $propertyOptionName): ?string
    {
        $propertyOptionData = [
            'id' => '',
            'name' => $propertyOptionName
        ];
        $createdPropertyOption = $this->shopwareRequest(
            'POST',
            'property-group/' . $propertyGroupId . '/options?_response=true',
            $propertyOptionData);

        if (empty($createdPropertyOption['data']['id'])) {
            return null;
        }

        return $createdPropertyOption['data']['id'];
    }

    /**
     * @param string $optionId
     * @param string $optionName
     * @param string $countryIsoCode
     */
    protected function createTranslationForPropertyOption($optionId, $optionName, $countryIsoCode): void
    {
        $languageId = $this->getLanguageIdByCountryIso($countryIsoCode);
        if (empty($languageId)) {
            return;
        }
        $headerInformation = ['sw-language-id: ' . $languageId];
        $translation = [
            'name' => $optionName,
        ];

        $this->shopwareRequest(
            'PATCH',
            sprintf('property-group-option/%s', $optionId),
            $translation,
            $headerInformation);
    }

    /**
     * @param array $internalArticle
     * @param string $articleIdShopware
     * @return array
     */
    protected function propertiesToExport($internalArticle, $articleIdShopware): array
    {
        $propertiesToAdd = $this->getPropertiesFromArticle($internalArticle);
        if (empty($propertiesToAdd)) {
            return [];
        }
        $assignedProperties = [];

        foreach ($propertiesToAdd as $propertyDefaultName => $countryIsoToPropertyTranslation) {
            if (empty($countryIsoToPropertyTranslation['DE'])) {
                continue;
            }
            $propertyGroupId = '';
            if (array_key_exists($propertyDefaultName, $this->knownPropertyGroupIds)) {
                $propertyGroupId = $this->knownPropertyGroupIds[$propertyDefaultName];
            }
            if (empty($propertyGroupId)) {
                $propertyGroupId = $this->getPropertyGroupId($propertyDefaultName);
            }
            if (empty($propertyGroupId)) {
                $propertyGroupId = $this->createPropertyGroup($propertyDefaultName);
            }
            if (empty($propertyGroupId)) {
                $this->Shopware6Log('PropertyGroup kann nicht erstellt werden: ' . $propertyDefaultName);
                continue;
            }

            foreach ($countryIsoToPropertyTranslation as $countryIsoCode => $translation) {
                $this->createTranslationForPropertyGroup($propertyGroupId, $translation['name'], $countryIsoCode);
            }


            $optionId = $this->getPropertyOptionId($propertyGroupId, $countryIsoToPropertyTranslation['DE']['value'], 'DE');
            if (empty($optionId)) {
                $optionId = $this->createPropertyOption($propertyGroupId, $countryIsoToPropertyTranslation['DE']['value']);
            }
            if (empty($optionId)) {
                $this->Shopware6Log('Option kann nicht erstellt werden: ' . $countryIsoToPropertyTranslation['DE']['value']);
                continue;
            }

            $assignedProperties[] = $optionId;

            foreach ($countryIsoToPropertyTranslation as $countryIsoCode => $translation) {
                $this->createTranslationForPropertyOption($optionId, $translation['value'], $countryIsoCode);
            }
        }

        if (!empty($articleIdShopware)) {
            $existingProperties = $this->shopwareRequest('GET', 'product/' . $articleIdShopware . '/properties?limit=100');
            foreach ($existingProperties['data'] as $existingProperty) {
                if (!in_array($existingProperty['id'], $assignedProperties, false)) {
                    $this->shopwareRequest('DELETE', 'product/' . $articleIdShopware . '/properties/' . $existingProperty['id']);
                }
            }
        }

        $propertiesToAdd = [];
        foreach ($assignedProperties as $propertyOptionId) {
            $propertiesToAdd[] = ['id' => $propertyOptionId];
        }

        return $propertiesToAdd;
    }

    /**
     * @param string $name
     * @param string $value
     * @return bool
     */
    protected function propertyMustBeIgnored(string $name, string $value): bool
    {
        return empty($value) ||
            strpos($name, 'customField_') === 0 ||
            stripos($name, 'shopware6_') !== false;
    }

    /**
     * @param array $internalArticleData
     * @return array
     */
    protected function getPropertiesFromArticle($internalArticleData): array
    {
        //'Farbe' => [['DE' => ['name' => 'Farbe, 'value' => 'Gelb']],
        //           ['EN' => ['name' => 'Colour, 'value' => 'Yellow']]]
        $propertiesToAdd = [];
        if (!empty($internalArticleData['eigenschaften'])) {
            foreach ($internalArticleData['eigenschaften'] as $property) {
                if ($this->propertyMustBeIgnored($property['name'], $property['values'])) {
                    continue;
                }
                if (strpos($property['name'], 'property_') === 0) {
                    $propertyName = substr($property['name'], 9);
                    $propertiesToAdd[$propertyName]['DE'] = [
                        'name' => $propertyName,
                        'value' => $property['values']];
                    continue;
                }
                if ($this->propertyOption === 'toProperties') {
                    $propertiesToAdd[$property['name']]['DE'] = [
                        'name' => $property['name'],
                        'value' => $property['values']];
                }
            }
        }

        if (!empty($internalArticleData['eigenschaftenuebersetzungen'])) {
            foreach ($internalArticleData['eigenschaftenuebersetzungen'] as $translatedProperty) {
                if ($translatedProperty['language_to'] === 'EN') {
                    $translatedProperty['language_to'] = 'GB';
                }
                if ($this->propertyMustBeIgnored($translatedProperty['property_to'], $translatedProperty['property_value_to'])) {
                    continue;
                }
                if (strpos($translatedProperty['property_to'], 'property_') === 0) {
                    $propertiesToAdd[$translatedProperty['property_from']][$translatedProperty['language_to']] = [
                        'name' => substr($translatedProperty['property_to'], 9),
                        'value' => $translatedProperty['property_value_to']];
                    continue;
                }
                if ($this->propertyOption === 'toProperties') {
                    $propertiesToAdd[$translatedProperty['property_from']][$translatedProperty['language_to']] = [
                        'name' => $translatedProperty['property_to'],
                        'value' => $translatedProperty['property_value_to']];
                }
            }
        }

        if (!empty($internalArticleData['freifelder'])) {
            foreach ($internalArticleData['freifelder']['DE'] as $freeFieldKey => $freeFieldValue) {
                if ($this->propertyMustBeIgnored($freeFieldKey, $freeFieldValue)) {
                    continue;
                }
                if (strpos($freeFieldKey, 'property_') === 0) {
                    $propertyName = substr($freeFieldKey, 9);
                    $propertiesToAdd[$propertyName]['DE'] = [
                        'name' => $propertyName,
                        'value' => $freeFieldValue
                    ];
                    continue;
                }
                if ($this->freeFieldOption === 'toProperties') {
                    $propertiesToAdd[$freeFieldKey]['DE'] = [
                        'name' => $freeFieldKey,
                        'value' => $freeFieldValue
                    ];
                }
            }

            foreach ($internalArticleData['freifelder'] as $languageIso => $freeFields) {
                if ($languageIso === 'DE') {
                    continue;
                }
                if ($languageIso === 'EN') {
                    $languageIso = 'GB';
                }
                foreach ($freeFields as $freeFieldData) {
                    if ($this->propertyMustBeIgnored($freeFieldData['mapping'], $freeFieldData['wert'])) {
                        continue;
                    }
                    if (strpos($freeFieldData['mapping'], 'property_') === 0) {
                        $propertyName = substr($freeFieldData['mapping'], 9);
                        $propertiesToAdd[$propertyName][$languageIso] = [
                            'name' => $propertyName,
                            'value' => $freeFieldData['wert']
                        ];
                        continue;
                    }
                    if ($this->freeFieldOption === 'toProperties') {
                        $propertiesToAdd[$freeFieldData['mapping']][$languageIso] = [
                            'name' => $freeFieldData['mapping'],
                            'value' => $freeFieldData['wert']
                        ];
                    }
                }
            }
        }

        return $propertiesToAdd;
    }

    /**
     * @param array $articleInXentral
     * @param string $articleIdShopware
     *
     * @return array
     */
    protected function customFieldsToExport($articleInXentral, $articleIdShopware): array
    {
        $customFieldsToAdd = $this->getCustomFieldsFromArticle($articleInXentral);
        if (empty($customFieldsToAdd)) {
            return [];
        }
        $languageId = $this->getLanguageIdByCountryIso('DE');
        $headerInformation = ['sw-language-id: ' . $languageId];

        $customFields = [];
        if (!empty($articleIdShopware)) {
            $articleInfo = $this->shopwareRequest(
                'GET', 'product/' . $articleIdShopware,
                [],
                $headerInformation);
            $customFields['DE'] = $articleInfo['data'][0]['attributes']['customFields'];
            if ($customFields === null) {
                $customFields = [];
            }
        }

        foreach ($customFieldsToAdd as $defaultFieldName => $countryIsoCodeToCustomFieldData) {
            $customFieldDefinition = $this->shopwareRequest(
                'GET',
                sprintf('custom-field?filter[custom_field.name]=%s', $defaultFieldName),
                [],
                $headerInformation
            );
            if (empty($customFieldDefinition)) {
                $this->Shopware6Log('Freifeld entspricht keinem shopware Freifeld', $defaultFieldName);
                continue;
            }

            foreach ($countryIsoCodeToCustomFieldData as $countryIsoCode => $customFieldData) {
                $name = $customFieldData['name'];
                $value = $customFieldData['value'];
                if ($value === '') {
                    continue;
                }
                if($countryIsoCode === 'EN'){
                    $countryIsoCode = 'GB';
                }
                $fieldType = $customFieldDefinition['data'][0]['attributes']['type'];
                $controlType = $customFieldDefinition['data'][0]['attributes']['config']['componentName'];

                switch ($fieldType) {
                    case 'text':
                    case 'html':
                        if ($controlType === 'sw-media-field') {
                            $this->Shopware6Log(
                                'Warnung: Freifelder vom Type "medium" werden nicht unterstützt.'
                            );
                        } else {
                            $customFields[$countryIsoCode][$name] = (string)$value;
                        }
                        break;
                    case 'bool':
                        $customFields[$countryIsoCode][$name] = filter_var($value, FILTER_VALIDATE_BOOLEAN);
                        break;
                    case 'int':
                        $customFields[$countryIsoCode][$name] = (int)$value;
                        break;
                    case 'float':
                        $customFields[$countryIsoCode][$name] = (float)$value;
                        break;
                    case 'select':
                        $options = $customFieldDefinition['data'][0]['attributes']['config']['options'];
                        $allowedValues = [];
                        foreach ($options as $option) {
                            $allowedValues[] = $option['value'];
                        }
                        if ($controlType === 'sw-single-select') {
                            if (in_array($value, $allowedValues, true)) {
                                $customFields[$countryIsoCode][$name] = $value;
                            } else {
                                $this->Shopware6Log(
                                    sprintf('Warnung: Freifeld "%s"="%s"; ungültiger Wert', $name, $value),
                                    ['allowed values' => $allowedValues]
                                );
                            }
                        }
                        if ($controlType === 'sw-multi-select') {
                            $value = explode(',', $value);
                            foreach ($value as &$item) {
                                $item = trim($item);
                            }
                            unset($item);
                            if (array_intersect($value, $allowedValues) === $value) {
                                $customFields[$countryIsoCode][$name] = $value;
                            } else {
                                $this->Shopware6Log(
                                    sprintf('Warnung: Freifeld "%s"; ungültiger Wert', $name),
                                    ['values' => $value, 'allowed values' => $allowedValues]
                                );
                            }
                        }
                        break;
                    default:
                        $this->Shopware6Log(
                            'Warnung: Freifeld enthält falschen Typ.',
                            ['freifeld' => $name, 'wert' => $value]
                        );
                        continue 2;
                }
            }
        }


        return $customFields;
    }

    /**
     * @param string $name
     * @param string $value
     * @return bool
     */
    protected function customFieldMustBeIgnored(string $name, string $value): bool
    {
        return empty($value) ||
            strpos($name, 'property_') === 0 ||
            stripos($name, 'shopware6_') !== false;
    }

    /**
     * @param array $articleInXentral
     * @return array
     */
    protected function getCustomFieldsFromArticle($articleInXentral): array
    {
        $customFieldsToAdd = [];
        if (!empty($articleInXentral['eigenschaften'])) {
            foreach ($articleInXentral['eigenschaften'] as $propertyInXentral) {
                if ($this->customFieldMustBeIgnored($propertyInXentral['name'], $propertyInXentral['values'])) {
                    continue;
                }
                if (strpos($propertyInXentral['name'], 'customField_') === 0) {
                    $customFieldName = substr($propertyInXentral['name'], 12);
                    $customFieldsToAdd[$customFieldName]['DE'] = [
                        'name' => $customFieldName,
                        'value' => $propertyInXentral['values']
                    ];
                    continue;
                }
                if ($this->propertyOption === 'toCustomFields') {
                    $customFieldsToAdd[$propertyInXentral['name']]['DE'] = [
                        'name' => $propertyInXentral['name'],
                        'value' => $propertyInXentral['values']
                    ];
                }
            }
        }
        if (!empty($articleInXentral['eigenschaftenuebersetzungen'])) {
            foreach ($articleInXentral['eigenschaftenuebersetzungen'] as $translatedProperty) {
                if ($this->customFieldMustBeIgnored($translatedProperty['property_to'], $translatedProperty['property_value_to'])) {
                    continue;
                }
                if (strpos($translatedProperty['property_to'], 'customField_') === 0) {
                    $customFieldName = substr($translatedProperty['property_to'], 12);
                    $customFieldsToAdd[$customFieldName][$translatedProperty['language_to']] = [
                        'name' => $customFieldName,
                        'value' => $translatedProperty['property_value_to']
                    ];
                    continue;
                }
                if ($this->propertyOption === 'toCustomFields') {
                    $customFieldsToAdd[$translatedProperty['property_to']][$translatedProperty['language_to']] = [
                        'name' => $translatedProperty['property_to'],
                        'value' => $translatedProperty['property_value_to']
                    ];
                }
            }
        }

        if (!empty($articleInXentral['freifelder'])) {
            foreach ($articleInXentral['freifelder']['DE'] as $freeFieldKey => $freeFieldValue) {
                if ($this->customFieldMustBeIgnored($freeFieldKey, $freeFieldValue)) {
                    continue;
                }
                if (strpos($freeFieldKey, 'customField_') === 0) {
                    $customFieldName = substr($freeFieldKey, 12);
                    $customFieldsToAdd[$customFieldName]['DE'] = [
                        'name' => $customFieldName,
                        'value' => $freeFieldValue
                    ];
                    continue;
                }
                if ($this->freeFieldOption === 'toCustomFields') {
                    $customFieldsToAdd[$freeFieldKey]['DE'] = [
                        'name' => $freeFieldKey,
                        'value' => $freeFieldValue
                    ];
                }
            }

            foreach ($articleInXentral['freifelder'] as $countryIsoCode => $freeFieldTranslations) {
                if ($countryIsoCode === 'DE') {
                    continue;
                }
                foreach ($freeFieldTranslations as $freeFieldTranslation){
                    if ($this->customFieldMustBeIgnored($freeFieldTranslation['mapping'], $freeFieldTranslation['wert'])) {
                        continue;
                    }
                    if ($countryIsoCode === 'EN') {
                        $countryIsoCode = 'GB';
                    }
                    if (strpos($freeFieldTranslation['mapping'], 'customField_') === 0) {
                        $customFieldName = substr($freeFieldTranslation['mapping'], 12);
                        $customFieldsToAdd[$customFieldName][$countryIsoCode] = [
                            'name' => $customFieldName,
                            'value' => $freeFieldTranslation['wert']
                        ];
                        continue;
                    }
                    if ($this->freeFieldOption === 'toCustomFields') {
                        $customFieldsToAdd[$freeFieldTranslation['mapping']][$countryIsoCode] = [
                            'name' => $freeFieldTranslation['mapping'],
                            'value' => $freeFieldTranslation['wert']
                        ];
                    }
                }
            }
        }

        return $customFieldsToAdd;
    }

    /**
     * @param array $articleInXentral
     * @param int $articleIdShopware
     *
     * @return array
     */
    protected function crosssellingToExport($articleInXentral, $articleIdShopware){
        if (empty($articleInXentral['crosssellingartikel'])) {
            return [];
        }

        $crosssellingArticles = [];
        foreach ($articleInXentral['crosssellingartikel'] as $crosssellingArticle){
            $type = 'Ähnlich';
            if($crosssellingArticle['art'] == 2){
                $type = 'Zubehör';
            }
            $crosssellingArticles[$type][] = $crosssellingArticle['nummer'];
        }
        $crossselingInformation = [];
        foreach ($crosssellingArticles as $type => $articles){
            if(!empty($articleIdShopware)){
                $existingCrossSellings = $this->shopwareRequest('GET', sprintf('product/%s/cross-sellings/',
                    $articleIdShopware));
                if(!empty($existingCrossSellings['data'])){
                    foreach ($existingCrossSellings['data'] as $existingCrossSelling){
                        if($existingCrossSelling['attributes']['name'] === $type){
                            $this->shopwareRequest('DELETE', sprintf('product/%s/cross-sellings/%s/',
                                $articleIdShopware, $existingCrossSelling['id']));
                        }
                    }
                }
            }

            $crosselingToAdd = [];
            foreach ($articles as $articleNumber) {
                $articleInfo = $this->shopwareRequest(
                    'GET',
                    sprintf('product?filter[product.productNumber]=%s', $articleNumber)
                );

                if(empty($articleInfo['data'][0]['id'])){
                    continue;
                }
                $crosselingToAdd[] = $articleInfo['data'][0]['id'];
            }
            if(empty($crosselingToAdd)){
                continue;
            }
            $crossselingInformationForType = [
                'active' => true,
                'name' => $type,
                'assignedProducts' => [],
                'type' => 'productList',
                'sortBy' => 'name',
                'limit' => 24,
                'position' => 1
            ];
            $position = 1;
            foreach ($crosselingToAdd as $articleId){
                $crossselingInformationForType['assignedProducts'][] = [
                    'productId' => $articleId,
                    'position' => $position,
                ];
                $position++;
            }
            $crossselingInformation[] = $crossselingInformationForType;
        }


        return $crossselingInformation;
    }

    /**
     * @param string $unitShortCode
     *
     * @return string
     */
    protected function unitToAdd(string $unitShortCode): string{
        $searchData = [
            'limit' => 25,
            'source' => [
                'id'
            ],
            'filter' => [
                [
                    'field' => 'unit.shortCode',
                    'type' => 'equals',
                    'value' => $unitShortCode
                ]
            ]
        ];
        $unitInShopware = $this->shopwareRequest(
            'POST',
            'search/unit',
            $searchData);

        if(!empty($unitInShopware['data'][0]['id'])){
            return $unitInShopware['data'][0]['id'];
        }

        $query = sprintf("SELECT `internebemerkung` FROM `artikeleinheit` WHERE `einheit_de` = '%s' LIMIT 1",
            $unitShortCode);
        $unitName = $this->app->DB->Select($query);
        if(empty($unitName)){
            $unitName = $unitShortCode;
        }

        $unitInformation = [
            'name' => $unitName,
            'shortCode' => $unitShortCode
        ];
        $result = $this->shopwareRequest('POST', 'unit?_response=true', $unitInformation);

        if(empty($result['data']['id'])){
            return '';
        }

        return $result['data']['id'];
    }

    /**
     * @param array $internArticle
     * @param int $articleIdShopware
     *
     * @return array
     */
    protected function systemFieldsToExport($internArticle, $articleIdShopware): array
    {
        $internalSpecialFields = [];
        foreach ($internArticle['freifelder']['DE'] as $freeFieldName => $freeFieldValue) {
            if (stripos($freeFieldName, 'shopware6_') !== false) {
                $internalSpecialFields[$freeFieldName] = $freeFieldValue;
            }
        }
        foreach ($internArticle['eigenschaften'] as $property) {
            if (stripos($property['name'], 'shopware6_') !== false) {
                $internalSpecialFields[$property['name']] = $property['values'];
            }
        }

        $systemFields = [];
        foreach ($internalSpecialFields as $fieldName => $fieldValue) {
            switch (strtolower($fieldName)) {
                case 'shopware6_sales_channel':
                    $systemFields['visibilities'] = $this->modifySalesChannel(explode(',', $fieldValue), $articleIdShopware);
                    break;
                case 'shopware6_purchase_unit':
                    $systemFields['purchaseUnit'] = (float)str_replace(',', '.', $fieldValue);
                    break;
                case 'shopware6_reference_unit':
                    $systemFields['referenceUnit'] = (float)str_replace(',', '.', $fieldValue);
                    break;
                case 'shopware6_unit':
                    $systemFields['unitId'] = $this->unitToAdd($fieldValue);
                    break;
                case 'shopware6_pack_unit':
                    $systemFields['packUnit'] = (string)$fieldValue;
                    break;
                case 'shopware6_restock_time':
                  $systemFields['restockTime'] = (int)$fieldValue;
                  break;
                case 'shopware6_pack_unit_plural':
                    $systemFields['packUnitPlural'] = (string)$fieldValue;
                    break;
            }
        }

        return $systemFields;
    }

    /**
     * @param array $salesChannelNames
     * @param string $articleIdInShopware
     *
     * @return array
     */
    protected function modifySalesChannel($salesChannelNames, $articleIdInShopware)
    {
        $salesChannelInXentralIds = [];
        foreach ($salesChannelNames as $salesChannelName) {
            $salesChannelInfo = $this->shopwareRequest('GET',
                sprintf('sales-channel?filter[sales_channel.name]=%s', urlencode(trim($salesChannelName)))
            );
            if (!empty($salesChannelInfo['data'][0]['id'])) {
                $salesChannelInXentralIds[] = $salesChannelInfo['data'][0]['id'];
            }
        }

        $existingVisibilities = $this->shopwareRequest(
            'GET',
            sprintf('product/%s/visibilities', $articleIdInShopware)
        );

        $existingSalesChannelIds = [];
        if (!empty($existingVisibilities['data'])) {
            foreach ($existingVisibilities['data'] as $visibility) {
                $existingSalesChannelIds[$visibility['id']] = $visibility['attributes']['salesChannelId'];
            }
        }

        foreach ($existingSalesChannelIds as $associationId => $existingSalesChannelId){
            if (!in_array($existingSalesChannelId, $salesChannelInXentralIds,true)) {
                $this->shopwareRequest('DELETE', sprintf('product/%s/visibilities/%s/',
                    $articleIdInShopware, $associationId));
            }
        }

        $salesChannelsToAdd = [];
        foreach ($salesChannelInXentralIds as $salesChannelInXentralId){
            if (!in_array($salesChannelInXentralId, $existingSalesChannelIds,true)) {
                $salesChannelsToAdd[] = $salesChannelInXentralId;
            }
        }

        $visibilities = [];
        foreach ($salesChannelsToAdd as $salesChannelIdToAdd) {
            $visibilities[] = [
                'salesChannelId' => $salesChannelIdToAdd,
                'visibility' => 30
            ];
        }

        return $visibilities;
    }

    /**
     * @param string $isoCode
     *
     * @return string
     */
    protected function findCurrencyId($isoCode)
    {

        $this->requestCurrencyMappingLazy();
        if (isset($this->currencyMapping[strtoupper($isoCode)])) {
            return $this->currencyMapping[strtoupper($isoCode)];
        }
        $this->Shopware6Log(
            sprintf('Warnung: Kein Mapping für Waehrung "%s" gefunden.', $isoCode),
            $this->currencyMapping
        );

        return null;
    }

    /**
     * request currency mapping only once
     */
    protected function requestCurrencyMappingLazy()
    {

        if ($this->currencyMapping !== null) {
            return;
        }
        $currencies = $this->shopwareRequest('GET', 'currency');
        if (!isset($currencies['data'])) {
            $this->Shopware6Log('Kann Währungsmapping nicht abrufen', $currencies);
        }
        foreach ($currencies['data'] as $currency) {
            $isoCode = strtoupper($currency['attributes']['isoCode']);
            $this->currencyMapping[$isoCode] = $currency['id'];
        }
    }

    /**
     * @param array $internalArticleData
     * @param string $articleIdInShopware
     * @return bool
     */
    public function exportSeoUrls(array $internalArticleData, string $articleIdInShopware): bool
    {
        if (empty($articleIdInShopware)) {
            return false;
        }

        $preparedSeoInformation = [];
        foreach ($internalArticleData['freifelder'] as $countryIsoCode => $freeFieldInformation) {
            if($countryIsoCode === 'EN'){
                $countryIsoCode = 'GB';
            }
            if($countryIsoCode === 'DE'){
                foreach ($freeFieldInformation as $freeFieldName => $freeFieldValue) {
                    if (stripos($freeFieldName, 'shopware6_seo_url') !== false) {
                        $preparedSeoInformation[$countryIsoCode][$freeFieldName] = $freeFieldValue;
                    }
                }
            }else{
                foreach ($freeFieldInformation as $freeFieldData) {
                    if (stripos($freeFieldData['mapping'], 'shopware6_seo_url') !== false) {
                        $preparedSeoInformation[$countryIsoCode][$freeFieldData['mapping']] = $freeFieldData['wert'];
                    }
                }
            }
        }
        foreach ($internalArticleData['eigenschaften'] as $property) {
            if (stripos($property['name'], 'shopware6_seo_url') !== false) {
                $preparedSeoInformation['DE'][$property['name']] = $property['values'];
            }
        }
        foreach ($internalArticleData['eigenschaftenuebersetzungen'] as $propertyTranslation) {
            if($propertyTranslation['language_to'] === 'EN'){
                $propertyTranslation['language_to'] = 'GB';
            }
            if (stripos($propertyTranslation['property_to'], 'shopware6_seo_url') !== false) {
                $preparedSeoInformation[$propertyTranslation['language_to']][$propertyTranslation['property_to']] = $propertyTranslation['property_value_to'];
            }
        }

        $specificSalesChannelSeoUrls = [];
        $defaultSeoUrls = [];
        foreach ($preparedSeoInformation as $countryIsoCode => $channelAssociations) {
            foreach ($channelAssociations as $fieldName => $fieldValue){
                if(strtolower($fieldName) === 'shopware6_seo_url'){
                    $defaultSeoUrls[$countryIsoCode] = $fieldValue;
                }else{
                    $seoInformation = explode('|', $fieldName);
                    $specificSalesChannelSeoUrls[$countryIsoCode][array_pop($seoInformation)] = $fieldValue;
                }
            }
        }

        if (empty($specificSalesChannelSeoUrls) && empty($defaultSeoUrls)) {
             return false;
        }

        $salesChannelsIdToName = [];
        $salesChannels = $this->shopwareRequest('GET','sales-channel');
        foreach ($salesChannels['data'] as $salesChannel) {
            $salesChannelsIdToName[$salesChannel['id']] = $salesChannel['attributes']['name'];
        }

        foreach ($preparedSeoInformation as $countryIsoCode => $x){
            $languageId = $this->getLanguageIdByCountryIso($countryIsoCode);
            if (empty($languageId)) {
                $this->Shopware6Log('Language Id not found for country: ' . $countryIsoCode);
                continue;
            }

            $headerInformation = ['sw-language-id: ' . $languageId];
            foreach ($salesChannelsIdToName as $salesChannelId => $salesChannelName) {
                $seoUrlToUse = $defaultSeoUrls[$countryIsoCode];
                if (!empty($specificSalesChannelSeoUrls[$countryIsoCode][$salesChannelName])) {
                    $seoUrlToUse = $specificSalesChannelSeoUrls[$countryIsoCode][$salesChannelsIdToName[$salesChannelName]];
                }
                if (empty($seoUrlToUse)) {
                    continue;
                }
                $seoDataToSend = [
                    'seoPathInfo' => $seoUrlToUse,
                    '_isNew' => true,
                    'isModified' => true,
                    'isCanonical' => true,
                    'isDeleted' => false,
                    'routeName' => 'frontend.detail.page',
                    'foreignKey' => $articleIdInShopware,
                    'pathInfo' => '/detail/'.$articleIdInShopware,
                    'languageId' => $languageId,
                    'salesChannelId' => $salesChannelId];
                $this->shopwareRequest('PATCH', '_action/seo-url/canonical', $seoDataToSend, $headerInformation);
            }
        }

        return true;
    }

    /**
     * @param array $article
     * @param string $articleIdShopware
     * @param string $currencyId
     *
     * @return bool
     */
    protected function exportVariants($article, $articleIdShopware, $currencyId): bool
    {
        $languageId = $this->getLanguageIdByCountryIso('DE');
        if (empty($languageId)) {
            return false;
        }
        if (empty($article['matrix_varianten']) || empty($articleIdShopware)) {
            return false;
        }
        $internalGroupPropertiesToShopwareId = [];
        foreach ($article['matrix_varianten']['gruppen'] as $propertyGroupName => $internalPropertyGroupValues) {
            $propertyGroupId = '';
            if (array_key_exists($propertyGroupName, $this->knownPropertyGroupIds)) {
                $propertyGroupId = $this->knownPropertyGroupIds[$propertyGroupName];
            }
            if (empty($propertyGroupId)) {
                $propertyGroupId = $this->getPropertyGroupId($propertyGroupName);
            }
            if (empty($propertyGroupId)) {
                $propertyGroupId = $this->createPropertyGroup($propertyGroupName);
            }
            if (empty($propertyGroupId)) {
                $this->Shopware6Log('PropertyGroup kann nicht erstellt werden: ' . $propertyGroupName);
                return false;
            }

            if (!empty($article['matrix_varianten']['texte'])) {
                $this->createTranslationForPropertyGroup($propertyGroupId, $propertyGroupName, 'DE');

                foreach ($article['matrix_varianten']['texte']['gruppen'] as $countryIsoCode => $matrixGroupTranslation) {
                    if ($countryIsoCode === 'EN') {
                        $countryIsoCode = 'GB';
                    }

                    $this->createTranslationForPropertyGroup($propertyGroupId, $matrixGroupTranslation[$propertyGroupName], $countryIsoCode);
                }
            }

            $languageId = $this->getLanguageIdByCountryIso('DE');
            $headerInformation = ['sw-language-id: ' . $languageId];
            $shopwarePropertyGroupOptions = $this->shopwareRequest(
                'GET',
                'property-group/' . $propertyGroupId . '/options?limit=100',
                $headerInformation);
            foreach ($shopwarePropertyGroupOptions['data'] as $shopwarePropertyGroupOption) {
                $propertyValue = $shopwarePropertyGroupOption['attributes']['name'];
                $internalGroupPropertiesToShopwareId[$propertyGroupName][$propertyValue] = $shopwarePropertyGroupOption['id'];
            }

            foreach ($internalPropertyGroupValues as $internalPropertyGroupValue => $valueNotNeeded) {
                if (!array_key_exists($internalPropertyGroupValue, $internalGroupPropertiesToShopwareId[$propertyGroupName])) {
                    $newOptionData = [
                        'name' => (string)$internalPropertyGroupValue
                    ];
                    $optionData = $this->shopwareRequest(
                        'POST',
                        'property-group/' . $propertyGroupId . '/options?_response=true',
                        $newOptionData);
                    $internalGroupPropertiesToShopwareId[$propertyGroupName][$internalPropertyGroupValue] = $optionData['data']['id'];
                }
            }

            if (!empty($article['matrix_varianten']['texte'])) {
                foreach ($internalPropertyGroupValues as $optionValue => $valueNotNeeded) {
                    $optionId = $internalGroupPropertiesToShopwareId[$propertyGroupName][$optionValue];
                    $this->createTranslationForPropertyOption(
                        $optionId,
                        $optionValue,
                        'DE');
                    foreach ($article['matrix_varianten']['texte']['werte'] as $countryIsoCode => $matrixOptionTranslations) {
                        if ($countryIsoCode === 'EN') {
                            $countryIsoCode = 'GB';
                        }
                        if (array_key_exists($optionValue, $matrixOptionTranslations)) {
                            $this->createTranslationForPropertyOption(
                                $optionId,
                                $matrixOptionTranslations[$optionValue],
                                $countryIsoCode);
                        }
                    }
                }
            }
        }

        $existingCombinations = $this->shopwareRequest(
            'GET',
            '_action/product/' . $articleIdShopware . '/combinations');
        $existingCombinationsByNumber = [];

        foreach ($existingCombinations as $combinationId => $combinationInfo) {
            $existingCombinationsByNumber[$combinationInfo['productNumber']] = [
                'id' => $combinationId,
                'options' => [],
            ];
            foreach ($combinationInfo['options'] as $combinationOption) {
                $existingCombinationsByNumber[$combinationInfo['productNumber']]['options'][$combinationOption] = $combinationOption;
            }
        }


        foreach ($article['artikel_varianten'] as $variant) {
            $internalVariantMatrixData = $article['matrix_varianten']['artikel'][$variant['artikel']];
            $productNumber = $internalVariantMatrixData[0]['nummer'];
            $name = $variant['name_de'];
            $stock = $variant['lag'];
            $ean = $variant['ean'];
            $weight = (float)$variant['gewicht'];
            $pseudoPrice = $variant['pseudopreis'];
            if (empty($pseudoPrice)) {
                $pseudoPrice = 0;
            }
            if (!empty($variant['pseudolager'])) {
                $stock = $variant['pseudolager'];
            }
            $active = true;
            if (!empty($variant['inaktiv'])) {
                $active = false;
            }
            $isCloseOut = false;
            if (!empty($variant['restmenge'])) {
                $isCloseOut = true;
            }

            $variantProductData = [
                'active' => $active,
                'isCloseout' => $isCloseOut,
                'name' => $name,
                'description' => null,
                'weight' => null,
                'price' => [
                    [
                        'currencyId' => $currencyId,
                        'gross' => $variant['bruttopreis'],
                        'net' => $variant['preis'],
                        'linked' => true,
                        'listPrice' => [
                            'currencyId' => $currencyId,
                            'gross' => $pseudoPrice,
                            'linked' => true,
                            'net' => $pseudoPrice / (1 + $variant['steuersatz'] / 100)
                        ]
                    ]
                ],
                'stock' => (int)$stock,
                'ean' => null,
                'taxId' => $this->getTaxIdByRate($variant['steuersatz']),
            ];
            if(!empty($weight)){
                $variantProductData['weight'] = $weight;
            }
            if(!empty($ean)){
                $variantProductData['ean'] = $ean;
            }
            if (!empty($variant['uebersicht_de'])) {
                $variantProductData['description'] = $variant['uebersicht_de'];
            }

            $renewVariant = false;
            $options = [];
            foreach ($internalVariantMatrixData as $expression) {
                if (!in_array(
                    $internalGroupPropertiesToShopwareId[$expression['name']][$expression['values']],
                    $existingCombinationsByNumber[$productNumber]['options'],
                    false)) {
                    $renewVariant = true;
                } else {
                    unset($existingCombinationsByNumber[$productNumber]['options'][$internalGroupPropertiesToShopwareId[$expression['name']][$expression['values']]]);
                }
                $options[] = ['id' => $internalGroupPropertiesToShopwareId[$expression['name']][$expression['values']]];
            }

            if (!empty($existingCombinationsByNumber[$productNumber]['options'])) {
                $renewVariant = true;
            }

            $variantImageData = [
                'Dateien' => []
            ];
            $variantProductId = '';
            if (!empty($existingCombinationsByNumber[$productNumber]['id']) && !$renewVariant) {
                $variantProductId = $existingCombinationsByNumber[$productNumber]['id'];
            }
            if (!empty($variant['Dateien']['id'])) {
                foreach ($variant['Dateien']['id'] as $index => $fileId) {
                    $variantImageData['Dateien'][] = [
                        'filename' => $variant['Dateien']['filename'][$index],
                        'extension' => $variant['Dateien']['extension'][$index],
                        'datei' => $variant['Dateien']['datei'][$index],
                        'beschreibung' => $variant['Dateien']['beschreibung'][$index],
                        'titel' => $variant['Dateien']['titel'][$index],
                        'id' => $fileId,
                    ];
                }
            }
            $mediaToAdd = $this->mediaToExport($variantImageData, $variantProductId);
            $variantProductData['media'] = $mediaToAdd;

            if ($renewVariant) {
                if (!empty($existingCombinationsByNumber[$productNumber]['id'])) {
                    $this->shopwareRequest('DELETE', 'product/' . $existingCombinationsByNumber[$productNumber]['id']);
                }
                $variantProductData['productNumber'] = $productNumber;
                $variantProductData['parentId'] = $articleIdShopware;
                $variantProductData['options'] = $options;

                $result = $this->shopwareRequest('POST', 'product?_response=true', $variantProductData);
                $variantProductId = $result['data']['id'];
            } else {
                $variantProductId = $existingCombinationsByNumber[$productNumber]['id'];
                $this->shopwareRequest('PATCH', 'product/' . $variantProductId, $variantProductData);
            }

            $defaultPrices = $this->getPricesFromArray($variant['staffelpreise_standard'] ?? []);
            $groupPrices = $this->getPricesFromArray($variant['staffelpreise_gruppen'] ?? []);

            $this->deleteOldBulkPrices($variantProductId);
            if (!empty($defaultPrices)) {
              foreach ($defaultPrices as $priceData) {
                $this->exportBulkPriceForGroup($variantProductId, $this->defaultRuleName, $priceData);
              }
            }
            if (!empty($groupPrices)) {
              foreach ($groupPrices as $priceData) {
                $this->exportBulkPriceForGroup($variantProductId, $priceData->getGroupName(), $priceData);
              }
            }

            $this->addCoverImage($variantImageData, $variantProductId);
        }

        $existingConfigurations = $this->shopwareRequest(
            'GET', 'product/' . $articleIdShopware . '/configuratorSettings');
        $optionIdsToAdd = [];
        foreach ($article['artikel_varianten'] as $variant) {
            foreach ($article['matrix_varianten']['artikel'][$variant['artikel']] as $matrixInfo) {
                $configurationExists = false;
                foreach ($existingConfigurations['data'] as $configuration) {
                    if ($configuration['attributes']['optionId'] === $internalGroupPropertiesToShopwareId[$matrixInfo['name']][$matrixInfo['values']]) {
                        $configurationExists = true;
                        break;
                    }
                }
                if (!$configurationExists) {
                    $optionIdsToAdd[] = $internalGroupPropertiesToShopwareId[$matrixInfo['name']][$matrixInfo['values']];
                }
            }
        }
        if (!empty($optionIdsToAdd)) {
            $optionIdsToAdd = array_flip(array_flip($optionIdsToAdd));
            $configurationData = [
                'configuratorSettings' => []
            ];
            foreach ($optionIdsToAdd as $id) {
                $configurationData['configuratorSettings'][] = ['optionId' => $id];
            }

            $this->shopwareRequest(
                'PATCH',
                sprintf('product/%s', $articleIdShopware),
                $configurationData
            );

            $existingConfigurations = $this->shopwareRequest(
                'GET', 'product/' . $articleIdShopware . '/configuratorSettings');
            $optionsToSort = [];
            foreach ($article['artikel_varianten'] as $variant) {
                foreach ($article['matrix_varianten']['artikel'][$variant['artikel']] as $matrixInfo) {
                    foreach ($existingConfigurations['data'] as $configuration) {
                        if ($configuration['attributes']['optionId'] === $internalGroupPropertiesToShopwareId[$matrixInfo['name']][$matrixInfo['values']]) {
                            $optionsToSort[] = $configuration['id'];
                            break;
                        }
                    }
                }
            }
            if (!empty($optionsToSort)) {
                $optionsToSort = array_flip(array_flip($optionsToSort));
                $configurationData = [
                    'configuratorSettings' => []
                ];
                $position = 1;

                foreach ($optionsToSort as $id) {
                    $configurationData['configuratorSettings'][] = [
                        'id' => $id,
                        'position' => $position];
                    $position++;
                }

                $this->shopwareRequest(
                    'PATCH',
                    sprintf('product/%s', $articleIdShopware),
                    $configurationData
                );
            }
        }

        return true;
    }

  /**
   * @param $priceArray
   * @return PriceData[]
   */
    protected function getPricesFromArray($priceArray): array{
      return array_map(static function($price){
        return new PriceData(
          (int)$price['ab_menge'],
          (float)$price['preis'],
          (float)$price['bruttopreis'],
          $price['waehrung'],
          $price['gruppeextern'] ?? '') ;
      },$priceArray);
    }

    /**
     * delete all old price entries for a product
     *
     * @param string $productId
     */
    protected function deleteOldBulkPrices($productId)
    {
      //TODO Instead of deleting all old prices we should rather check first whether they are still in order
        $oldPrices = $this->shopwareRequest(
            'GET',
            sprintf('product-price?filter[product_price.productId]=%s', $productId)
        );
        if (is_array($oldPrices)) {
            foreach ($oldPrices['data'] as $deletePrice) {
                $this->shopwareRequest('DELETE', 'product-price/' . $deletePrice['id']);
            }
        } else {
            $this->Shopware6Log('Fehler: Alte Preise wurden nicht gelöscht', $productId);
        }
    }

    /**
     * @return int
     */
    public function getOrderSearchLimit(): int
    {
      if(in_array($this->orderSearchLimit, ['50', '75', '100'])) {
        return (int)$this->orderSearchLimit;
      }

      return 25;
    }

    /**
     * @return int
     */
    public function ImportGetAuftraegeAnzahl()
    {
        $order = null;
        $dataToGet = $this->CatchRemoteCommand('data');

        if (empty($this->statesToFetch)) {
          return false;
        }

        $ordersToProcess = $this->getOrdersToProcess($this->getOrderSearchLimit());

        return (!empty(count($ordersToProcess['data'])?count($ordersToProcess['data']):0));
    }

    /**
     * @param string $parameter1
     * @param string $parameter2
     */
    public function Shopware6ErrorLog($parameter1, $parameter2 = '')
    {
        $this->app->DB->Insert(
            sprintf(
                "INSERT INTO `shopexport_log` 
             (shopid, typ, parameter1, parameter2, bearbeiter, zeitstempel) 
            VALUES (%d, 'fehler', '%s','%s','%s',NOW())",
                $this->shopid,
                $this->app->DB->real_escape_string($parameter1),
                $this->app->DB->real_escape_string($parameter2),
                $this->app->DB->real_escape_string($this->app->User->GetName())
            )
        );
    }

    /**
     * @param array $stateMachinesIds
     * @return array
     */
    protected function getTransactionStateIdsToFetch($stateMachinesIds): array
    {
        $transactionStateIdsToFetch = [];
        if (!empty($this->transactionStatesToFetch)) {
            $transactionStatesToFetch = explode(';', $this->transactionStatesToFetch);
            foreach ($transactionStatesToFetch as $transactionStateToFetch) {
                $stateInformation = $this->shopwareRequest('GET', 'state-machine-state?filter[technicalName]=' .
                    trim($transactionStateToFetch) . '&filter[stateMachineId]=' . $stateMachinesIds['order_transaction.state']);
                if (empty($stateInformation['data'])) {
                    $this->Shopware6ErrorLog('Zahlungsstatus für Abholung nicht gefunden', $transactionStateToFetch);
                    return false;
                }
                foreach ($stateInformation['data'] as $state) {
                    $transactionStateIdsToFetch[] = $state['id'];
                }
            }
        }

        return $transactionStateIdsToFetch;
    }

    /**
     * @param int $limit
     *
     * @return mixed
     */
    protected function getOrdersToProcess(int $limit)
    {
        $searchData = [
            'limit' => $limit,
            'includes' => [
                'order' => ['id']
            ],
            'sort' => [
                [
                    'field' => 'order.createdAt',
                    'direction' => 'DESC'
                ]
            ],
            'filter' => []
        ];

        $searchData['filter'][] = [
            'field' => 'stateMachineState.technicalName',
            'type' => 'equalsAny',
            'value' => explode(';', $this->statesToFetch)
        ];

        if (!empty($this->deliveryStatesToFetch)) {
            $searchData['filter'][] = [
                'field' => 'deliveries.stateMachineState.technicalName',
                'type' => 'equalsAny',
                'value' => explode(';', $this->deliveryStatesToFetch)
            ];
        }
        if (!empty($this->transactionStatesToFetch)) {
            $searchData['filter'][] = [
                'field' => 'transactions.stateMachineState.technicalName',
                'type' => 'equalsAny',
                'value' => explode(';', $this->transactionStatesToFetch)
            ];
        }

        if (!empty($this->salesChannelToFetch)) {
            $searchData['filter'][] = [
                'field' => 'order.salesChannelId',
                'type' => 'equals',
                'value' => $this->salesChannelToFetch
            ];
        }

        return $this->shopwareRequest('POST', 'search/order', $searchData);
    }

    /**
     * @return int|mixed
     */
    public function ImportGetAuftrag()
    {
        $voucherArticleId = $this->app->DB->Select("SELECT s.artikelrabatt FROM `shopexport` AS `s` WHERE s.id='$this->shopid' LIMIT 1");
        $voucherArticleNumber = $this->app->DB->Select("SELECT a.nummer FROM `artikel` AS `a` WHERE a.id='$voucherArticleId' LIMIT 1");

        $dataToGet = $this->CatchRemoteCommand('data');
        if (empty($this->statesToFetch)) {
            return false;
        }
        $expectOrderArray = !empty($dataToGet['anzgleichzeitig']) && (int)$dataToGet['anzgleichzeitig'] > 1;
        $expectNumber = !empty($dataToGet['nummer']);
        $order = null;
        if($expectNumber) {
            $order = $this->shopwareRequest('GET', 'order/' . $dataToGet['nummer'] . '?associations[currency][]');
            if(empty($order['data'])) {
                return false;
            }
            $ordersToProcess = ['data' => [ ['id' => $dataToGet['nummer']] ]];
            $orderIncludedData = $order['included'];
            $order = $order['data'];
        }
        elseif(!$expectOrderArray) {
          $ordersToProcess = $this->getOrdersToProcess(1);
        }
        elseif(!$expectNumber) {
          $ordersToProcess = $this->getOrdersToProcess($this->getOrderSearchLimit());
        }
        if (empty($ordersToProcess['data'])) {
            return false;
        }

        $fetchedOrders = [];
        if (isset($ordersToFetch['data']['id']) && !isset($ordersToFetch['data'][0])) {
            $ordersToFetch['data'] = [$ordersToFetch['data']];
        }
        foreach ($ordersToProcess['data'] as $currentlyOpenOrder) {
            $orderIdToFetch = $currentlyOpenOrder['id'];

            if (empty($dataToGet['nummer']) || empty($order)) {
                $order = $this->shopwareRequest('GET', 'order/' . $orderIdToFetch.'?associations[currency][]');
                $orderIncludedData = $order['included'];
                $order = $order['data'];
            }
            $cart = [];
            try {
                $timestamp = date_create_from_format('Y-m-d\TH:i:s+', $order['attributes']['createdAt']);
                $cart['zeitstempel'] = $timestamp->format('Y-m-d H:i:s');
            } catch (Exception $ex) {

            }
            $cart['auftrag'] = $order['id'];
            $cart['subshop'] = $order['attributes']['salesChannelId'];
            $cart['order'] = $order;
            $cart['onlinebestellnummer'] = $order['attributes']['orderNumber'];
            $cart['gesamtsumme'] = $order['attributes']['amountTotal'];
            $cart['versandkostenbrutto'] = $order['attributes']['shippingTotal'];
            $cart['bestelldatum'] = substr($order['attributes']['orderDate'], 0, 10);
            if (!empty($order['attributes']['customerComment'])) {
                $cart['freitext'] = $order['attributes']['customerComment'];
            }

            foreach ($orderIncludedData as $includedDataSet){
                if($includedDataSet['type'] === 'currency'){
                    $cart['waehrung'] = $includedDataSet['attributes']['isoCode'];
                }
            }

            $deliveryInfo = $this->shopwareRequest('GET', 'order/' . $order['id'] . '/deliveries');
            $shippingMethod = $this->shopwareRequest('GET',
                'order-delivery/' . $deliveryInfo['data'][0]['id'] . '/shipping-method');
            $order['shippingMethod'] = $shippingMethod;
            $cart['lieferung'] = $shippingMethod['data'][0]['attributes']['name'];

            $customer = $this->shopwareRequest('GET', 'order/' . $order['id'] . '/order-customer');
            $order['customer'] = $customer;
            $cart['email'] = $customer['data']['0']['attributes']['email'];

            $addresses = $this->shopwareRequest('GET', 'order/' . $order['id'] . '/addresses?associations[salutation][]&associations[country][]');
            $order['addresses'] = $addresses;
            $deliveryCountryId = '';
            $billingCountryId = '';
            $billingSalutationId = '';
            foreach ($addresses['data'] as $address) {
                if ($address['id'] === $order['attributes']['billingAddressId']) {
                    if (!empty($address['attributes']['vatId'])) {
                        $cart['ustid'] = $address['attributes']['vatId'];
                    }
                    $cart['name'] = $address['attributes']['firstName'] . ' ' . $address['attributes']['lastName'];
                    if (!empty($address['attributes']['company'])) {
                        $cart['ansprechpartner'] = $cart['name'];
                        $cart['name'] = $address['attributes']['company'];
                    }
                    $cart['strasse'] = $address['attributes']['street'];
                    $cart['abteilung'] = $address['attributes']['department'];
                    $cart['adresszusatz'] = trim($address['attributes']['additionalAddressLine1'].' '.
                      $address['attributes']['additionalAddressLine2']);
                    $cart['telefon'] = $address['attributes']['phoneNumber'];
                    $cart['plz'] = $address['attributes']['zipcode'];
                    $cart['ort'] = $address['attributes']['city'];
                    $billingCountryId = $address['attributes']['countryId'];
                    $billingSalutationId = $address['attributes']['salutationId'];
                }
                if ($address['id'] !== $order['attributes']['billingAddressId']) {
                    $cart['abweichendelieferadresse'] = 1;
                    if (!empty($address['attributes']['vatId'])) {
                        $cart['lieferadresse_ustid'] = $address['attributes']['vatId'];
                    }
                    $cart['lieferadresse_name'] = $address['attributes']['firstName'] . ' ' . $address['attributes']['lastName'];
                    if (!empty($address['attributes']['company'])) {
                        $cart['lieferadresse_ansprechpartner'] = $cart['lieferadresse_name'];
                        $cart['lieferadresse_name'] = $address['attributes']['company'];
                    }
                    $cart['lieferadresse_strasse'] = $address['attributes']['street'];
                    $cart['lieferadresse_abteilung'] = $address['attributes']['department'];
                    $cart['lieferadresse_adresszusatz'] = trim($address['attributes']['additionalAddressLine1'].' '.
                    $address['attributes']['additionalAddressLine2']);
                    $cart['lieferadresse_plz'] = $address['attributes']['zipcode'];
                    $cart['lieferadresse_ort'] = $address['attributes']['city'];
                    $deliveryCountryId = $address['attributes']['countryId'];
                }
            }

            $anrede = 'herr';
            $land = 'DE';
            $lieferadresseLand = 'DE';
            foreach ($addresses['included'] as $includedInfo) {
                if ($includedInfo['id'] === $billingCountryId) {
                    $land = $includedInfo['attributes']['iso'];
                }
                if ($includedInfo['id'] === $deliveryCountryId) {
                    $lieferadresseLand = $includedInfo['attributes']['iso'];
                }
                if ($includedInfo['id'] === $billingSalutationId) {
                    $salutation = $includedInfo['attributes']['salutationKey'];
                    if ($salutation === 'ms' || $salutation === 'mrs') {
                        $anrede = 'frau';
                    }
                }
            }

            $cart['anrede'] = $anrede;
            $cart['land'] = $land;
            if (!empty($cart['abweichendelieferadresse'])) {
                $cart['lieferadresse_land'] = $lieferadresseLand;
            }

            $transactionData = $this->shopwareRequest('GET', 'order/' . $order['id'] . '/transactions');
            $cart['transacion_data'] = $transactionData;
            if (!empty($transactionData['data'][0]['attributes']['customFields']['swag_paypal_pui_payment_instruction']['reference_number'])) {
                $cart['transaktionsnummer'] = $transactionData['data'][0]['attributes']['customFields']['swag_paypal_pui_payment_instruction']['reference_number'];
            }
            if (empty($cart['transaktionsnummer'] && !empty($transactionData['data'][0]['attributes']['customFields']['swag_paypal_order_id']))) {
                $cart['transaktionsnummer'] = (string)$transactionData['data'][0]['attributes']['customFields']['swag_paypal_order_id'];
            }
            if (empty($cart['transaktionsnummer'] && !empty($transactionData['data'][0]['attributes']['customFields']['swag_paypal_transaction_id']))) {
                $livePayPalData = $this->shopwareRequest('GET', 'paypal/payment-details/' . $order['id'] . '/' . $transactionData['data'][0]['attributes']['customFields']['swag_paypal_transaction_id']);
                if (!empty($livePayPalData['transactions'])) {
                    foreach ($livePayPalData['transactions'] as $payPalData) {
                        foreach ($payPalData['related_resources'] as $ressources) {
                            if ($ressources['sale']['state'] === 'completed') {
                                $cart['transaktionsnummer'] = $ressources['sale']['id'];
                                break 2;
                            }
                        }
                    }
                }
            }
            if(
                empty($cart['transaktionsnummer'])
                && isset($transactionData['data'][0]['attributes']['customFields']['stripe_payment_context']['payment']['payment_intent_id'])
            ){
                $cart['transaktionsnummer'] = $transactionData['data'][0]['attributes']['customFields']['stripe_payment_context']['payment']['payment_intent_id'];
            }

            $paymentMethodId = $transactionData['data'][0]['attributes']['paymentMethodId'];
            $paymentMethod = $this->shopwareRequest('GET', 'payment-method/' . $paymentMethodId);
            $cart['zahlungsweise'] = $paymentMethod['data']['attributes']['name'];

            $taxedCountry = $land;
            if($this->taxationByDestinationCountry){
                $taxedCountry = $lieferadresseLand;
            }
            if($order['attributes']['amountTotal'] === $order['attributes']['amountNet']){
                if($this->app->erp->IstEU($taxedCountry)){
                    $cart['ust_befreit'] = 1;
                }elseif($this->app->erp->Export($taxedCountry)){
                    $cart['ust_befreit'] = 2;
                }else{
                    $cart['ust_befreit'] = 3;
                }
            }

            $lineItems = $this->shopwareRequest('GET', 'order/' . $order['id'] . '/line-items');
            $order['lineItems'] = $lineItems;
            $cart['articlelist'] = [];

            $taxRate = 0;
            foreach ($lineItems['data'] as $lineItem) {
                if ($lineItem['attributes']['price']['calculatedTaxes'][0]['taxRate'] > $taxRate) {
                    $taxRate = $lineItem['attributes']['price']['calculatedTaxes'][0]['taxRate'];
                }
            }

            $orderPriceType = 'price';
            if(in_array($order['attributes']['taxStatus'], ['net', 'tax-free'])) {
                $orderPriceType = 'price_netto';
                $cart['versandkostennetto'] = $cart['versandkostenbrutto'];
                unset($cart['versandkostenbrutto']);
            }

            foreach ($lineItems['data'] as $lineItem) {
                $productPriceType = $orderPriceType;
                if(empty($lineItem['attributes']['price']['calculatedTaxes'][0]['taxRate'])){
                    $productPriceType = 'price_netto';
                }
                $articleId = null;
                if($lineItem['attributes']['price']['unitPrice'] < 0) {
                  $articleId = $voucherArticleNumber;
                }
                elseif(isset($lineItem['attributes']['payload']['productNumber'])){
                  $articleId = $lineItem['attributes']['payload']['productNumber'];
                }
                $product = [
                    'articleid' => $articleId,
                    'name' => $lineItem['attributes']['label'],
                    'quantity' => $lineItem['attributes']['quantity'],
                    $productPriceType => $lineItem['attributes']['price']['unitPrice'],
                    'steuersatz' => $lineItem['attributes']['price']['calculatedTaxes'][0]['taxRate'],
                ];
                $cart['articlelist'][] = $product;
            }

            $cart['order'] = $order;
            $fetchedOrders[] = [
                'id' => $cart['auftrag'],
                'sessionid' => '',
                'logdatei' => '',
                'warenkorb' => base64_encode(serialize($cart)),
                'warenkorbjson' => base64_encode(json_encode($cart)),
            ];
            $this->Shopware6Log('Ergebnis: Auftrag', $order);
            $this->Shopware6Log('Ergebnis: Adresse', $addresses);
            $this->Shopware6Log('Ergebnis: Positionen', $lineItems);
        }

        return $fetchedOrders;
    }

    /**
     * @return void
     */
    public function ImportDeleteAuftrag()
    {
        $tmp = $this->CatchRemoteCommand('data');
        $auftrag = $tmp['auftrag'];

        $this->shopwareRequest('POST', '_action/order/'.$auftrag.'/state/process');
        $this->addCustomFieldToOrder((string)$auftrag);
    }

    /**
     * @return void
     */
    public function ImportUpdateAuftrag()
    {
        $tmp = $this->CatchRemoteCommand('data');
        $auftrag = $tmp['auftrag'];
        $tracking = $tmp['tracking'];

        $this->shopwareRequest('POST', '_action/order/'.$auftrag.'/state/complete');

        $deliveries = $this->shopwareRequest('GET', 'order/'.$auftrag.'/deliveries');
        $deliveryId = $deliveries['data'][0]['id'];

        if(!empty($deliveryId)){
            $this->shopwareRequest('POST', '_action/order_delivery/'.$deliveryId.'/state/ship');

            $deliveryData = [
                'trackingCodes' => [$tracking]
            ];
            $this->shopwareRequest('PATCH', 'order-delivery/'.$deliveryId,$deliveryData);
        }

        $this->sendInvoce($auftrag);
        $this->addCustomFieldToOrder((string)$auftrag);
        if(empty($tmp['orderId'])) {
            return;
        }
        $this->updateStorageForOrderIntId((int)$tmp['orderId']);
    }

    public function ImportStorniereAuftrag()
    {
        $tmp = $this->CatchRemoteCommand('data');
        $auftrag = $tmp['auftrag'];

        $this->shopwareRequest('POST', '_action/order/'.$auftrag.'/state/cancel');
        $this->addCustomFieldToOrder((string)$auftrag);
    }

    /**
     * @param string $extOrderId
     */
    protected function sendInvoce($extOrderId)
    {
        $order = $this->app->DB->SelectRow(
            sprintf(
                "SELECT `rechnungid`, `id` FROM `auftrag` WHERE shopextid='%s'",
                $extOrderId
            )
        );
        $invoiceId = 0;
        if (!empty($order['rechnungid'])) {
            $invoiceId = $order['rechnungid'];
            $sql = sprintf("SELECT projekt, belegnr FROM rechnung WHERE id='%s'", $invoiceId);
            $invoiceData = $this->app->DB->SelectRow($sql);
        }
        if (empty($invoiceId) && !empty($order['id'])) {
            $invoiceData = $this->app->DB->SelectRow(
                sprintf(
                    "SELECT `id`, `projekt`, `belegnr` 
                      FROM `rechnung` 
                      WHERE `auftragid` = %d AND `status` <> 'storniert' AND `status` <> 'angelegt' 
                      LIMIT 1",
                    $order['id']
                )
            );
            if (!empty($invoiceData)) {
                $invoiceId = $invoiceData['id'];
            }
        }

        if (!empty($invoiceData['belegnr'])) {
            $projekt = $invoiceData['projekt'];
            if (class_exists('RechnungPDFCustom')) {
                $Brief = new RechnungPDFCustom($this->app, $projekt);
            } else {
                $Brief = new RechnungPDF($this->app, $projekt);
            }

            $Brief->GetRechnung($invoiceId);
            $filePath = $Brief->displayTMP(true);

            $documentNumber = $invoiceData['belegnr'];
            $invoiceDocumentData = [
                'config' => [
                    'custom' => [
                        'invoiceNumber' => $documentNumber,
                    ],
                    'documentComment' => 'Aus Xentral heraus erstellte Rechnung',
                    'documentNumber' => $documentNumber,
                ],
                'referenced_document_id' => null,
                'static' => true
            ];

            $documentData = $this->shopwareRequest('POST', '_action/order/' . $extOrderId . '/document/invoice', $invoiceDocumentData);
            $documentId = $documentData['documentId'];

            $accessToken = $this->shopwareToken();
            $url = $this->ShopUrl . '_action/document/' . $documentId . '/upload?_response=true&extension=pdf&fileName=' . $documentNumber;

            $ch = curl_init();
            $setHeaders = [
                'Content-Type:application/pdf',
                'Authorization:Bearer ' . $accessToken['token']
            ];
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_POSTFIELDS, file_get_contents($filePath));
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
            curl_setopt($ch, CURLOPT_HTTPHEADER, $setHeaders);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            $response = json_decode(curl_exec($ch), true);
            curl_close($ch);
            if (!empty($response['errors'])) {
                $this->Shopware6Log(
                    'Fehler bei Rechnugnsübertragung für ' . $documentNumber, $response['errors']
                );
            }
        }
    }

    /**
     * @return string
     */
    public function ImportAuth()
    {
        $tokeninfo = $this->shopwareToken();


        if (!$tokeninfo['success']) {
            return 'failed: ' . $tokeninfo['message'];
        }
        if($this->data === 'info'){
            $salesChannelsInShopware = $this->client->getAllSalesChannels();
            $salesChannelsToShow = ['subshops' => []];
            foreach ($salesChannelsInShopware['data'] as $salesChannelInShopware){
                $salesChannelsToShow['subshops'][] = [
                    'id'=>$salesChannelInShopware['id'],
                    'name'=>$salesChannelInShopware['name'],
                    'aktiv'=>$salesChannelInShopware['active']
                ];
            }
            return $salesChannelsToShow;
        }

        return 'success';
    }

    /**
     * Build category tree as displayed in article info
     * May be useful for setting category in the future
     * but probably obsolete
     *
     * @param string $categoryName
     * @param array $categoryTree
     *
     * @return array
     */
    protected function appendCategoryTree($categoryName, $categoryTree = [])
    {
        $shopwareCategory = $this->shopwareRequest(
            'GET',
            'category?filter[category.name]=' . urlencode($categoryName)
        );
        if (!isset($shopwareCategory['data'][0]['id'])) {
            return $categoryTree;
        }
        $categoryInfo = $shopwareCategory['data'][0]['attributes'];
        $categories[] = [(int)$categoryInfo['level'], $shopwareCategory['data'][0]['id']];
        $path = $categoryInfo['path'];
        if (!empty($path)) {
            $pathArray = explode('|', $path);
            foreach ($pathArray as $nodeId) {
                if ($nodeId === '') {
                    continue;
                }
                $nodeCategory = $this->shopwareRequest('GET', 'category/' . $nodeId);
                if (isset($nodeCategory['data']['id'])) {
                    $categories[] = [(int)$nodeCategory['data']['attributes']['level'], $nodeId];
                    unset($nodeCategory);
                }
            }
        }
        foreach ($categories as $category) {
            $level = $category[0];
            if (!isset($categoryTree[$level])) {
                $categoryTree[$level] = [];
            }
            if (!in_array($category, $categoryTree[$level], true)) {
                $categoryTree[$level][] = $category[1];
            }
        }
        ksort($categoryTree);

        return $categoryTree;
    }

  /**
   * @param array $postData
   *
   * @return array
   */
    public function updatePostDataForAssistent($postData)
    {
      if(!empty($this->ShopUrl)) {
        $postData['shopwareUrl'] = $this->ShopUrl;
      }
      return $postData;
    }

  /**
   * @param array $shopArr
   * @param array $postData
   *
   * @return array
   */
    public function updateShopexportArr($shopArr, $postData)
    {
      $shopArr['stornoabgleich'] = 1;
      $shopArr['demomodus'] = 0;

      return $shopArr;
    }

  /**
   * @return JsonResponse|null
   */
    public function AuthByAssistent()
    {
      $shopwareUrl = $this->app->Secure->GetPOST('shopwareUrl');
      $shopwareUserName = $this->app->Secure->GetPOST('shopwareUserName');
      $shopwarePassword = $this->app->Secure->GetPOST('shopwarePassword');
      $step = (int)$this->app->Secure->GetPOST('step');

      if($step <= 1){
        if(empty($shopwareUrl)){
          return new JsonResponse(['error' => 'Bitte die URL des Shops angeben.'], JsonResponse::HTTP_BAD_REQUEST);
        }
        if(empty($shopwareUserName)){
          return new JsonResponse(['error' => 'Bitte den Benutzernamen angeben'], JsonResponse::HTTP_BAD_REQUEST);
        }
        if(empty($shopwarePassword)){
          return new JsonResponse(['error' => 'Bitte das Passwort angeben'], JsonResponse::HTTP_BAD_REQUEST);
        }

        $this->UserName = $shopwareUserName;
        $this->Password = $shopwarePassword;
        $shopwareUrl = rtrim($shopwareUrl, '/') . '/';
        $testUrls = [];
        $hasNoHttp = strpos($shopwareUrl,'http') !== 0;
        if(substr($shopwareUrl, -5) !== '/api/') {
          if($hasNoHttp) {
            $testUrls[] = 'https://'.$shopwareUrl.'api/';
            $testUrls[] = 'http://'.$shopwareUrl.'api/';
          }
          $testUrls[] = $shopwareUrl.'api/';
        }
        elseif($hasNoHttp) {
          $testUrls[] = 'https://'.$shopwareUrl;
          $testUrls[] = 'http://'.$shopwareUrl;
        }
        else {
          $testUrls[] = $shopwareUrl;
        }
        foreach($testUrls as $testUrl) {
          $this->ShopUrl = $testUrl;
          $tokeninfo = $this->shopwareToken();
          if(!empty($tokeninfo['success'])) {
            break;
          }
        }

        if(!$tokeninfo['success']){
          return new JsonResponse(['error' => $tokeninfo['message']], JsonResponse::HTTP_BAD_REQUEST);
        }
      }

      return null;
    }

  /**
   * @return string
   */
    public function getClickByClickHeadline()
    {
      return 'Bitte im Shopware Backend einen eigenen Benutzer für Xentral anlegen und diese 
      Zugangsdaten hier eintragen.';
    }

  /**
   * @return array
   */
    public function getStructureDataForClickByClickSave()
    {
      return [
        'shopwareAllowCreateManufacturer' => 1,
      ];
    }

  /**
   * @return array[]
   */
    public function getCreateForm()
    {
      return [
        [
          'id' => 0,
          'name' => 'urls',
          'inputs' => [
            [
              'label' => 'URL des Shops',
              'type' => 'text',
              'name' => 'shopwareUrl',
              'validation' => true,
            ],
          ],
        ],
        [
          'id' => 1,
          'name' => 'username',
          'inputs' => [
            [
              'label' => 'Benutzername aus Shopware',
              'type' => 'text',
              'name' => 'shopwareUserName',
              'validation' => true,
            ],
          ],
        ],
        [
          'id' => 2,
          'name' => 'password',
          'inputs' => [
            [
              'label' => 'Passwort aus Shopware',
              'type' => 'password',
              'name' => 'shopwarePassword',
              'validation' => true,
            ],
          ],
        ],
      ];
    }

    public function getBoosterHeadline(): string
    {
      return 'Shopware 6 Business Booster App';
    }

    public function getBoosterSubHeadline(): string
    {
      return 'Bitte gehe auf Shopware 6 und installiere dort das Plugin Xentral Business Booster App.
      Dort kann man sich dann mit ein paar Klicks mit Xentral verbinden.';
    }

  /**
   * @param int $intOrderId
   *
   * @return array
   */
    protected function getArticleShopLinks(int $intOrderId): array
    {
      return $this->app->DB->SelectPairs(
        "SELECT DISTINCT ao.artikel, a.nummer
        FROM `auftrag_position` AS `ap`
        INNER JOIN `auftrag` AS `ab` ON ap.auftrag = ab.id
        INNER JOIN `artikel` AS `a` ON ap.artikel = a.id 
        INNER JOIN `artikel_onlineshops` AS `ao` ON ab.shop = ao.shop AND a.id = ao.artikel 
        WHERE ab.id = {$intOrderId} AND ao.aktiv = 1"
      );
    }

    /**
     * @param array $articleIds
     */
    protected function updateArticleCacheToSync(array $articleIds): void
    {
      if(empty($articleIds)) {
        return;
      }
      $articleIdsString = implode(', ', $articleIds);
      $this->app->DB->Update(
        "UPDATE `artikel` 
        SET `laststorage_changed` = DATE_ADD(NOW(), INTERVAL 1 SECOND) 
        WHERE `id` IN ({$articleIdsString})"
      );
    }

    /**
     * @param array $articleIds
     */
    protected function updateArticleOnlineShopCache(array $articleIds): void
    {
      if(empty($articleIds)) {
        return;
      }
      $articleIdsString = implode(', ', $articleIds);
      $this->app->DB->Update(
        "UPDATE `artikel_onlineshops` 
        SET `storage_cache` = -999, `pseudostorage_cache` = -999 
        WHERE `artikel` IN ({$articleIdsString}) AND `aktiv` = 1 AND `shop` = {$this->shopid}"
      );
    }

    /**
     * @param int $intOrderId
     */
    protected function updateStorageForOrderIntId(int $intOrderId): void
    {
      $articles = $this->getArticleShopLinks($intOrderId);
      if(empty($articles)) {
        return;
      }
      $articleIds = array_keys($articles);
      $this->updateArticleCacheToSync($articleIds);
      $this->updateArticleOnlineShopCache($articleIds);

      $isStorageSyncCronjobActive = (int)$this->app->DB->Select(
          "SELECT COUNT(`id`) FROM `prozessstarter` WHERE `aktiv` = 1 AND `parameter` = 'lagerzahlen'"
        ) > 0;
      if(!$isStorageSyncCronjobActive) {
        return;
      }
      foreach($articleIds as $articleId) {
        try {
          $this->app->erp->LagerSync($articleId, false, [$this->shopid]);
        }
        catch (Exception $e) {
          $articleNumber = $articles[$articleId];
          $this->Shopware6ErrorLog('LagerSync konnte nicht ausgeführt werden', $articleNumber);
        }
      }

      $this->updateArticleCacheToSync($articleIds);
    }
}