<?php

namespace App\SAP;

use Carbon\Carbon;
use RuntimeException;
use SoapWrapper;
use stdClass;

/**
 * Wrapper class to access SAP SOAP endpoints
 */
class SAPClient {
    const SAP_TIMEZONE = 'Europe/Lisbon';

    /**
     * Constructor.
     */
    public function __construct()
    {
        SoapWrapper::add('Products', function ($service) {
            $service
                ->wsdl(config('sap.materials_wsdl_url'))
                ->options([
                    'login' => config('sap.api_username'),
                    'password' => config('sap.api_password')
                ])
                ->trace(true);
            }
        );

        SoapWrapper::add('Customer', function ($service) {
            $service
              ->wsdl(config('sap.customer_wsdl_url'))
              ->options([
                'login' => config('sap.api_username'),
                'password' => config('sap.api_password')
              ])
              ->trace(true);
        });

        SoapWrapper::add('Order', function ($service) {
            $service
              ->wsdl(config('sap.order_wsdl_url'))
              ->options([
                'login' => config('sap.api_username'),
                'password' => config('sap.api_password')
              ])
              ->trace(true);
        });

        SoapWrapper::add('OrderStatus', function ($service) {
            $service
              ->wsdl(config('sap.order_status_wsdl_url'))
              ->options([
                'login' => config('sap.api_username'),
                'password' => config('sap.api_password')
              ])
              ->trace(true);
        });
    }

    /**
     * Gets all product related data from webservice
     *
     */
    public function getMaterials($from = '0', $to = '0', $pricesOnly = false)
    {
        $response = SoapWrapper::call('Products.ZWsMaterials',
            [
                [
                    "IFrom" => $from,
                    "ITo" => $to,
                    "IPricesonly" => $pricesOnly ? 'X' : '',
                    "IZstore" => "1010"
                ]
            ]
        );

        if ($response->Zmessage) {
            throw new \RuntimeException("Error fetching materials: " . $response->Zmessage);
        }
        return $response;
    }

    /**
     * Gets all products ids
     */
    public function getProductIds()
    {
        $response = SoapWrapper::call('Products.ZWsMaterials', [
                [
                    "IPricesonly" => "A",
                    "IZstore" => "1010"
                ]
            ]
        );

        if ($response->Zmessage) {
            throw new \RuntimeException("Error fetching ids: " . $response->Zmessage);
        }
        return array_map(function($product) {
            return $product->Matnr;
        }, $response->TMaterials->item);
    }

    /**
     * Creates a customer in SAP - not used
     *
     * @param stdClass $customerData
     * @return void
     */
    public function createCustomer(stdClass $customerData)
    {
        $zwsCustomer = new stdClass();
        $zwsCustomer->WCustomer = $customerData;

        $response = SoapWrapper::call('Customer.ZWsCustomer', [
            $zwsCustomer
        ]);

        if ($response->Zmessage) {
            throw new \RuntimeException("Error creating SAP customer: " . $response->Zmessage);
        }

        return $response->ZparIdocnum;
    }

    /**
     * Creates an order in SAP
     *
     * @param stdClass $orderData
     * @param Array $items
     * @return string SAP id
     */
    public function createOrder(stdClass $orderData, Array $items)
    {
        $zwsOrderCreate = new stdClass();

        $zwsOrderCreate->TOrderItem = $items;
        $zwsOrderCreate->WOrderHeader = $orderData;
        // var_dump($zwsOrderCreate); die;
        $response = SoapWrapper::call('Order.ZWsOrderCreation', [
            $zwsOrderCreate
        ]);

        if ($response->Zmessage) {
            throw new \RuntimeException("Error creating SAP order: " . $response->Zmessage);
        }

        return $response->ZparIdocnum;
    }

    /**
     * Gets order status updates
     */
    public function getOrdersStatus(Carbon $fromDateTime)
    {
        $sapTimezoneDate = $fromDateTime->setTimezone(self::SAP_TIMEZONE);
        $fromDate = $sapTimezoneDate->format('Y-m-d');
        $fromTime = $sapTimezoneDate->format('H:i:s');
        \Log::info('Order status check since ' . $fromDate . ' - ' . $fromTime);
        $response = SoapWrapper::call('OrderStatus.ZWsOrderStatus', [
                [
                    "IChangesSince" => $fromDate,
                    "IChangesSinceT" => $fromTime,
                    "IOrderFrom" => null,
                    "IOrderTo" => null
                ]
            ]
        );

        if ($response->Zmessage && $response->Zmessage !== 'No changes were found.') {
            throw new \RuntimeException("Error fetching status for orders...: " . $response->Zmessage);
        }

        return !empty($response->TStatus->item) ? $response->TStatus->item : [];
    }

    /**
     * Gets order status for a specific order
     */
    public function getOrderStatus(int $shopifyId)
    {
        $response = SoapWrapper::call('OrderStatus.ZWsOrderStatus', [
                [
                    "IChangesSince" => null,
                    "IChangesSinceT" => null,
                    "IOrderFrom" => $shopifyId . '',
                    "IOrderTo" => $shopifyId . ''
                ]
            ]
        );

        if ($response->Zmessage && $response->Zmessage !== 'No changes were found.') {
            throw new \RuntimeException("Error fetching status for orders...: " . $response->Zmessage);
        }

        return !empty($response->TStatus->item) ? $response->TStatus->item : [];
    }
}
