<?php

require_once(_PS_MODULE_DIR_ . 'mbeshipping' . DIRECTORY_SEPARATOR . 'lib/mbe/MbeWs.php');
require_once(dirname(__FILE__) . '/helper/Data.php');
require_once(dirname(__FILE__) . '/helper/Logger.php');
require_once(dirname(__FILE__) . '/helper/Csv.php');
require_once(dirname(__FILE__) . '/helper/Rates.php');
require_once(dirname(__FILE__) . '/helper/Package.php');
require_once(dirname(__FILE__) . '/helper/PackageProduct.php');
require_once(dirname(__FILE__) . '/helper/Order.php');
require_once(dirname(__FILE__) . '/helper/UpsUap.php');

class Mbe_Shipping_Model_Ws
{
    private $helper;
    protected $logger = null;
    private $ws;

    public function __construct()
    {
        $this->helper = new Mbe_Shipping_Helper_Data();
        $this->logger = new Mbe_Shipping_Helper_Logger();

        $wsLogPath = _PS_MODULE_DIR_ . 'mbeshipping' . DIRECTORY_SEPARATOR . 'log';
        $this->ws = new MbeWs($wsLogPath);

    }

    public function getCustomer($forceUpdate=false)
    {
        if($forceUpdate || is_null(Configuration::get('MBECustomer')) || !Configuration::get('MBECustomer')) {
            $result = false;

            $wsUrl = $this->helper->getWsUrl();
            $wsUsername = $this->helper->getWsUsername();
            $wsPassword = $this->helper->getWsPassword();
            $system = $this->helper->getCountry();

            $cacheString = $wsUrl . $wsUsername . $wsPassword . $system;
            $cacheId = 'Mbe_Shipping_Model_Ws::getCustomer_' . md5($cacheString);

            if (version_compare(_PS_VERSION_, '1.5', '<')) {
                if ($wsUrl && $wsUsername && $wsPassword) {
                    $result = $this->ws->getCustomer($wsUrl, $wsUsername, $wsPassword, $system);
                    $this->logger->logDebug($result, 'WS getCustomer');
                }
            }
            else {
                /*if (Cache::isStored($cacheId)) {

                    $result = Cache::retrieve($cacheId);
                    $this->logger->logDebug('Customer found in cache');
                }
                else {*/
                    $this->logger->logDebug('Customer not found in cache');
                    if ($wsUrl && $wsUsername && $wsPassword) {
                        $result = $this->ws->getCustomer($wsUrl, $wsUsername, $wsPassword, $system);
                        $this->logger->logDebug($result, 'WS getCustomer');
                        /*if ($result) {
                            Cache::store($cacheId, $result);
                            $this->logger->logDebug('Saved customer to cache ' . $cacheId, $result);
                        }*/
                    }
                //}
            }
            return $result;
        }
        else
        {
            return json_decode(Configuration::get('MBECustomer'));
        }
    }

    public function getCustomerPermission($permissionName)
    {
        $result = null;
        $customer = $this->getCustomer();
        if ($customer) {
            $result = $customer->Permissions->$permissionName;
        }

        return $result;
    }

    public function getAvailableOptions()
    {
        $wsUrl = $this->helper->getWsUrl();
        $wsUsername = $this->helper->getWsUsername();
        $wsPassword = $this->helper->getWsPassword();
        $result = false;
        if ($wsUrl && $wsUsername && $wsPassword) {
            $result = $this->ws->getAvailableOptions($wsUrl, $wsUsername, $wsPassword);
        }

        return $result;
    }

    public function getAllowedShipmentServices()
    {
        $result = array();
        $customer = $this->getCustomer();
        if ($customer && $customer->Enabled) {
            if (isset($customer->Permissions->enabledServices)) {
                $enabledServices = $customer->Permissions->enabledServices;
                $enabledServicesDesc = $customer->Permissions->enabledServicesDesc;

                $enabledServicesArray = explode(",", $enabledServices);
                $enabledServicesDescArray = explode(",", $enabledServicesDesc);

                for ($i = 0; $i < count($enabledServicesArray); $i++) {
                    $service = $enabledServicesArray[$i];
                    $serviceDesc = $enabledServicesDescArray[$i];

                    $serviceDesc .= ' (' . $service . ')';

                    $currentShippingType = array(
                        'value' => $service,
                        'label' => $serviceDesc,
                    );

                    if (!in_array($currentShippingType, $result)) {
                        array_push($result, $currentShippingType);
                    }

                    //SHIPPING WITH INSURANCE
                    if (isset($customer->Permissions->canSpecifyInsurance) && $customer->Permissions->canSpecifyInsurance) {
                        $currentShippingWithInsuranceType = array(
                            'value' => $this->helper->convertShippingCodeWithInsurance($service),
                            'label' => $this->helper->convertShippingLabelWithInsurance($serviceDesc),
                        );
                        if (!in_array($currentShippingWithInsuranceType, $result)) {
                            array_push($result, $currentShippingWithInsuranceType);
                        }
                    }
                }
            }
        }
        return $result;
    }

    public function getLabelFromShipmentType($shipmentCode)
    {
        $result = $shipmentCode;
        $allowedShipmentServices = $this->getAllowedShipmentServices();
        foreach ($allowedShipmentServices as $allowedShipmentService) {
            if ($allowedShipmentService["value"] == $shipmentCode) {
                $result = $allowedShipmentService["label"];
                break;
            }
        }
        return $result;
    }

    private function convertInsuranceShipping($shippingList)
    {
        $result = false;
        if ($shippingList) {
            $newShippingList = array();
            foreach ($shippingList as $shipping) {

                if ($shipping->InsuranceAvailable) {
                    $newShipping = $shipping;
                    $newShipping->Service = $this->helper->convertShippingCodeWithInsurance($newShipping->Service);
                    $newShipping->ServiceDesc = $this->helper->convertShippingLabelWithInsurance($newShipping->ServiceDesc);
                    array_push($newShippingList, $newShipping);
                }
            }
            if (!empty($newShippingList)) {
                $result = $newShippingList;
            }
        }
        return $result;
    }

    public function estimateShipping($country, $region, $postCode, $weight, $boxes, $insuranceValue, $allowedShipmentServicesArray)
    {
        $this->logger->logDebug('ESTIMATESHIPPING');
        $wsUrl = $this->helper->getWsUrl();
        $wsUsername = $this->helper->getWsUsername();
        $wsPassword = $this->helper->getWsPassword();
        $system = $this->helper->getCountry();

        $result = false;

        if ($wsUrl && $wsUsername && $wsPassword) {
            $length = $this->helper->getDefaultLength();
            $width = $this->helper->getDefaultWidth();
            $height = $this->helper->getDefaultHeight();

            $shipmentType = $this->helper->getDefaultShipmentType();

            $items = $this->setItems($weight);


            $this->logger->logDebug($items, 'ESTIMATESHIPPING ITEMS');

            //Shipping without insurance
            $resultWithoutInsurance = $this->ws->estimateShipping($wsUrl, $wsUsername, $wsPassword, $shipmentType, $system, $country, $region, $postCode, $items, false, $insuranceValue);

            //Shipping with insurance
            if (preg_match("/INSURANCE/", var_export($allowedShipmentServicesArray, true))) {
                $resultWithInsurance = $this->ws->estimateShipping($wsUrl, $wsUsername, $wsPassword, $shipmentType, $system, $country, $region, $postCode, $items, true, $insuranceValue);
                $resultWithInsurance = $this->convertInsuranceShipping($resultWithInsurance);
            }
            else
            {
                $resultWithInsurance = null;
            }

            if ($resultWithInsurance && $resultWithoutInsurance) {
                $result = array_merge($resultWithInsurance, $resultWithoutInsurance);
            }
            else {
                if ($resultWithInsurance) {
                    $result = $resultWithInsurance;
                }
                if ($resultWithoutInsurance) {
                    $result = $resultWithoutInsurance;
                }
            }
        }
        return $result;
    }


    public function createShipping($country, $region, $postCode, $weight, $boxes, $products, $service, $notes, $firstName, $lastName, $companyName, $address, $phone, $city, $email, $goodsValue = 0.0, $reference = "", $isCod = false, $codValue = 0.0, $insurance = false, $insuranceValue = 0.0, $uap = false, $uapID = -1)
    {
        $this->logger->logDebug('CREATE SHIPPING');

        $wsUrl = $this->helper->getWsUrl();
        $wsUsername = $this->helper->getWsUsername();
        $wsPassword = $this->helper->getWsPassword();
        $system = $this->helper->getCountry();
        $result = false;
        if ($wsUrl && $wsUsername && $wsPassword) {


            $length = $this->helper->getDefaultLength();
            $width = $this->helper->getDefaultWidth();
            $height = $this->helper->getDefaultHeight();

            $shipmentType = $this->helper->getDefaultShipmentType();

            $items = $this->setItems($weight);

            $this->logger->logDebug('CREATE SHIPPING ITEMS');
            $this->logger->logDebug($items);

            $shipperType = $this->getShipperType();
			$notes = mb_substr($notes, 0, 50, 'utf8');
            $result = $this->ws->createShipping($wsUrl, $wsUsername, $wsPassword, $shipmentType, $service, $system, $notes, $firstName, $lastName, $companyName, $address, $phone, $city, $region, $country, $postCode, $email, $items, $products, $shipperType, $goodsValue, $reference, $isCod, $codValue, $insurance, $insuranceValue, $uap, $uapID);
        }
        return $result;
    }

    public function getShipperType()
    {
        //COURIERLDV or MBE
        $customer = $this->getCustomer();
        $shipperType = "MBE";
        if ($customer->Permissions->canCreateCourierWaybill) {
            $shipperType = "COURIERLDV";
        }

        return $shipperType;
    }

    public function mustCloseShipments()
    {
        $result = true;
        $customer = $this->getCustomer();
        if ($customer->Permissions->canCreateCourierWaybill) {
            $result = false;
        }
        return $result;
    }

    public function getCustomerMaxParcelWeight()
    {
        $customer = $this->getCustomer();
        return $customer->Permissions->maxParcelWeight;
    }

    public function getCustomerMaxShipmentWeight()
    {
        $customer = $this->getCustomer();
        return $customer->Permissions->maxShipmentWeight;
    }

    public function isCustomerActive()
    {
        $result = false;
        $customer = $this->getCustomer();
        if ($customer) {
            $result = $customer->Enabled;
        }
        return $result;
    }

    public function closeShipping(array $shipmentIds)
    {
        $orderHelper =  new Mbe_Shipping_Helper_Order();
        $trackingNumbers = array();
        if (version_compare(_PS_VERSION_, '1.5', '<')) {
            foreach ($shipmentIds as $shipmentId) {
                $shipment = new Order((int)$shipmentId);

                $tracks = array_filter(explode(Mbe_Shipping_Helper_Data::MBE_SHIPPING_TRACKING_SEPARATOR, $shipment->shipping_number), function ($value) {
                    return $value !== '';
                });
                foreach ($tracks as $track) {
                    if(strpos($track, 'RETURN') == false) {
                        array_push($trackingNumbers, $track);
                    }
                }
                $order = new Order($shipmentId);
                $orderHelper->setOrderShipped($order);
            }
        }
        else {
            foreach ($shipmentIds as $shipmentId) {
                $shipment = new Order((int)$shipmentId);
                $oc = $this->helper->getOrderCarrier((int)$shipmentId);

                $tracks = array_filter(explode(Mbe_Shipping_Helper_Data::MBE_SHIPPING_TRACKING_SEPARATOR, $oc->tracking_number), function ($value) {
                    return $value !== '';
                });
                foreach ($tracks as $track) {
                    if(strpos($track, 'RETURN') == false) {
                        array_push($trackingNumbers, $track);
                    }
                }
                $order = new Order($shipmentId);
                $orderHelper->setOrderShipped($order);
            }
        }
        $this->closeTrackingNumbers($trackingNumbers);
    }

    public function closeTrackingNumbers(array $trackingNumbers)
    {
        $this->logger->logDebug('CLOSE SHIPPING');

        $wsUrl = $this->helper->getWsUrl();
        $wsUsername = $this->helper->getWsUsername();
        $wsPassword = $this->helper->getWsPassword();
        $system = $this->helper->getCountry();

        $result = false;

        if ($wsUrl && $wsUsername && $wsPassword) {
            $result = $this->ws->closeShipping($wsUrl, $wsUsername, $wsPassword, $system, $trackingNumbers);

            if ($result) {
                foreach ($trackingNumbers as $trackingNumber) {
                    $filePath = $this->helper->getTrackingFilePath($trackingNumber);
                    file_put_contents($filePath, $result->Pdf);
                }
            }
        }

        return $result;
    }

    public function setItems($boxesWeight)
    {
        $items = [];
        foreach ($boxesWeight as $box) {
            foreach ($box['weight'] as $weight) {
                $item = new \stdClass;
                $item->Weight = $weight;
                $item->Dimensions = new \stdClass;
                $item->Dimensions->Lenght = $box['dimensions']['length'];
                $item->Dimensions->Height = $box['dimensions']['height'];
                $item->Dimensions->Width = $box['dimensions']['width'];
                $items[] = $item;
            }
        }
        return $items;
    }

    public function createReturnShipping($tracking)
    {
        $this->logger->logDebug('CREATE RETURN SHIPPING');

        $wsUrl = $this->helper->getWsUrl();
        $wsUsername = $this->helper->getWsUsername();
        $wsPassword = $this->helper->getWsPassword();
        $system = $this->helper->getCountry();
        $result = false;
        if ($wsUrl && $wsUsername && $wsPassword) {
            $result = $this->ws->createReturnShipping($wsUrl, $wsUsername, $wsPassword, $system, $tracking);
        }
        return $result;
    }
}
