<?php
/**
 * 2016 Eengine Sp. z o.o.
 *
 * NOTICE OF LICENSE
 *
 */
if (!defined('_PS_VERSION_')) {
    exit;
}
require_once(dirname(__FILE__) . '/InpostModel.php'); //AR


class CrossBorderConnector
{
    const INPOST_GEOWIDGET_SK = 'https://geowidget-sk.easypack24.net/';
    const INPOST_GEOWIDGET_CZ = 'https://geowidget-cz.easypack24.net/';
    const INPOST_GEOWIDGET_PL = 'https://geowidget-pl.easypack24.net/';
    const INPOST_GEOWIDGET_FR = 'https://geowidget-fr.easypack24.net/';
    const INPOST_COUNTRY_3 = 'IT';
    const FILE = 'crossborderconnector';
    public $password;
    public function __construct()
    {
        $this->api_url = "https://api-xborder-inpost.sheepla.com/";

        if ((int)Configuration::get('INPOST_AVAILABLE_SERVICES_CROSSBORDER') === 1 || Tools::isSubmit('INPOST_AVAILABLE_SERVICES_CROSSBORDER')) {
            $token = self::getTokenFromConfiguration();
            if (!$token || property_exists($token, 'error') || (int)$token->expires_in < 3700) {
                $token = $this->getToken();
                Configuration::updateValue('INPOST_TOKEN_X_BORDER', serialize($token));
            }

            if (!$token || property_exists($token, 'error')) {
                return false;
            } else {
                $this->password = $token->access_token;
            }
        }

    }


    private function makeCurl($path, $fields = [], $method = 'GET', $getToken = false)
    {
        $headers = array();
        if ($this->password && !$getToken) {
            $headers[] = "Authorization: Bearer $this->password";
        }

        $ch = curl_init($this->api_url.$path);

        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
        curl_setopt($ch, CURLOPT_TIMEOUT, 15);
        if ($fields || $method === 'POST') {
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, Tools::jsonEncode($fields));
            $headers[] = "Content-Type: application/json";
        }
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        if (strpos($path, 'sticker') !== false) {
            $response =  curl_exec($ch);
        } else {
            $response = Tools::jsonDecode(curl_exec($ch));
        }

        curl_close($ch);
        return $response;
    }
    public function getToken()
    {
        $path = "/access-token";
        $fields = array(
            'client_id' => 'f37576be',
            'client_secret' => '80ed25d617be442f9929b6d6acc69fe0',
            'grant_type' => 'password',
            'username' => Configuration::get('INPOST_X_BORDER_LOGIN'),
            'password' => Configuration::get('INPOST_X_BORDER_PASSWORD')
        );

        return $this->makeCurl($path, $fields, 'POST', true);
    }
    public function getUserRoutesServices()
    {
        $path = "/users/me/routes/services";

        return $this->makeCurl($path, [], 'GET');
    }

    public function createParcel()
    {
        $inpost = Module::getInstanceByName('inpost');

        if (!$this->password)
        {
            return [
                'error' => 1,
                0 => $inpost->l('CrossBorder configuration not found', self::FILE)
            ];
        }
        $dispatch_points_id = 0;
        $receiver_pop_id = '';

        $dispatch_points_id = Tools::getValue('dispatch_points_sender');
        $method_giving = Tools::getValue('method_giving');

        if ($dispatch_points_id && $method_giving == 'dispatch_point') {
            $dispatch_point = InpostModel::getDispatchPointFieldsToEditValues($dispatch_points_id);
            if (!$dispatch_point) {
                return [
                    'error' => 1,
                    0 => $inpost->l('Dispatch point is not available', self::FILE)
                ];
            }
        }

        $currency = 'PLN';

        $receiver = Tools::getValue('receiver');

        $sender = Tools::getValue('sender');
//        $parcel_size = Tools::getValue('parcel_size');
        $sizesInCm = array(
            'height' => 0,
            'length' => 0,
            'width' => 0
        );
        $sizes = array(
            'height' => Tools::getValue('parcel_height'),
            'length' => Tools::getValue('parcel_length'),
            'unit' => Tools::getValue('parcel_size_unit'),
            'width' => Tools::getValue('parcel_width')
        );
        if ($sizes['unit'] == 'mm') {
            $sizesInCm['height'] = $sizes['height'] / 10;
            $sizesInCm['length'] = $sizes['length'] / 10;
            $sizesInCm['width'] = $sizes['width'] / 10;
        } elseif ($sizes['unit'] == 'm') {
            $sizesInCm['height'] = $sizes['height'] * 100;
            $sizesInCm['length'] = $sizes['length'] * 100;
            $sizesInCm['width'] = $sizes['width'] * 100;
        } else {
            $sizesInCm['height'] = $sizes['height'];
            $sizesInCm['length'] = $sizes['length'];
            $sizesInCm['width'] = $sizes['width'];
        }


        $iso_code_receiver = InpostModel::getCountryIsoCodeById($receiver['country']);
        $receiverParcelLocker = $this->getPop($receiver['parcel_locker']);

        if (!is_array($receiverParcelLocker) && property_exists($receiverParcelLocker, 'id')) {
            $receiver_pop_id = $receiverParcelLocker->id;
        }

        $pops = $this->getPopsInCountry('receipent', $iso_code_receiver);

        if ($receiver['parcel_locker'] && !$receiver_pop_id) {
            foreach ($pops as $pop) {
                if ($pop->code == strtoupper($iso_code_receiver).$receiver['parcel_locker']) {
                    $receiver_pop_id = $pop->id;
                }
            }
            if (!$receiver_pop_id) {
                return array(
                    'error' => 1,
                    0 => $inpost->l('Parcel locker receiver not found', self::FILE)
                );
            }
        }

        if (isset($sender['source_machine_id'])) {
            foreach ($pops as $pop) {
                if ($pop->code == $sender['source_machine_id']) {
                    $sender_pop_id = $pop->id;
                }
            }

        }

//        a. B2B
//        - 64x41x38 (gabaryt c)
        if ($receiver_pop_id && $sender_pop_id)
        {
            $sumOfDimension = 0;
            $cc = 0;
            foreach ($sizesInCm as $singleSizeInCm) {
                $sumOfDimension += $singleSizeInCm;
                if ($singleSizeInCm > 64) {
                    $cc++;
                }
                if ($singleSizeInCm > 41) {
                    $cc++;
                }
                if ($singleSizeInCm > 38) {
                    $cc++;
                }
            }

            if ($cc >= 4 || $sumOfDimension > 143) {
                return [
                    'error' => 1,
                    0 => $inpost->l('Maximum parcel size that can be delivered to the parcel locker is: 41 x 38 x 64 cm')
                ];
            }
            $canBeA = true;
            if ($sizesInCm['width'] > 8 || $sizesInCm['length'] > 8 || $sizesInCm['height'] > 8) {
                $canBeA = false;
            }
            $canBeB = true;
            if ($sizesInCm['width'] > 19 || $sizesInCm['length'] > 19 || $sizesInCm['height'] > 19) {
                $canBeB = false;
            }
            if ($sumOfDimension <= 110 && $canBeA) {
                $parcel_size = 'A';
            } elseif ($sumOfDimension > 100 && $sumOfDimension <= 121 && $canBeB) {
                $parcel_size = 'B';
            } else {
                $parcel_size = 'C';
            }


        }

//        b.  B2D
//        - 60x40x38 (miks dla dwóch wytycznych)
        if (isSet($sender_pop_id) && !$receiver_pop_id)
        {
            $sumOfDimension = 0;
            $cc = 0;
            foreach ($sizesInCm as $singleSizeInCm) {
                $sumOfDimension += $singleSizeInCm;
                if ($singleSizeInCm > 60) {
                    $cc++;
                }
                if ($singleSizeInCm > 40) {
                    $cc++;
                }
                if ($singleSizeInCm > 38) {
                    $cc++;
                }
            }

            if ($cc >= 4 || $sumOfDimension > 138) {
                return [
                    'error' => 1,
                    0 => $inpost->l('Maximum parcel size that can be send from the parcel locker is: 40 x 38 x 60 cm')
                ];
            }
            $canBeA = true;
            if ($sizesInCm['width'] > 8 || $sizesInCm['length'] > 8 || $sizesInCm['height'] > 8) {
                $canBeA = false;
            }
            $canBeB = true;
            if ($sizesInCm['width'] > 19 || $sizesInCm['length'] > 19 || $sizesInCm['height'] > 19) {
                $canBeB = false;
            }
            if ($sumOfDimension <= 110 && $canBeA) {
                $parcel_size = 'A';
            } elseif ($sumOfDimension > 100 && $sumOfDimension <= 121 && $canBeB) {
                $parcel_size = 'B';
            } else {
                $parcel_size = 'C';
            }
        }
//        d. D2B (export z Polski)
//                - 60x40x38
        if (!isSet($sender_pop_id) && $receiver_pop_id)
        {
            $sumOfDimension = 0;
            $cc = 0;
            foreach ($sizesInCm as $singleSizeInCm) {
                $sumOfDimension += $singleSizeInCm;
                if ($singleSizeInCm > 60) {
                    $cc++;
                }
                if ($singleSizeInCm > 40) {
                    $cc++;
                }
                if ($singleSizeInCm > 38) {
                    $cc++;
                }
            }

            if ($cc >= 4 || $sumOfDimension > 138) {
                return [
                    'error' => 1,
                    0 => $inpost->l('Maximum parcel size that can be delivered to the parcel locker is: 40 x 38 x 60 cm')
                ];
            }
            $canBeA = true;
            if ($sizesInCm['width'] > 8 || $sizesInCm['length'] > 8 || $sizesInCm['height'] > 8) {
                $canBeA = false;
            }
            $canBeB = true;
            if ($sizesInCm['width'] > 19 || $sizesInCm['length'] > 19 || $sizesInCm['height'] > 19) {
                $canBeB = false;
            }
            if ($sumOfDimension <= 110 && $canBeA) {
                $parcel_size = 'A';
            } elseif ($sumOfDimension > 100 && $sumOfDimension <= 121 && $canBeB) {
                $parcel_size = 'B';
            } else {
                $parcel_size = 'C';
            }
        }

        $parcel_weight = str_replace(',', '.',Tools::getValue('parcel_weight'));

        $parcel_weight_unit = Tools::getValue('parcel_weight_unit');
        if ($receiver['parcel_locker'] || isset($sender_pop_id)) {
            $parcel_weight_in_kg = $parcel_weight;
            if ($parcel_weight_unit == 'g') {
                $parcel_weight_in_kg = $parcel_weight / 1000;
            }
            if ($parcel_weight_in_kg > 20) {
                return [
                    'error' => 1,
                    0 => $inpost->l('Maximum parcel weight that can be delivered to parcel locker is: 20KG')
                ];
            }
        }
        $order = new Order(Tools::getValue('id_order'));
        $amountTotal = $order->total_paid_tax_incl;
        $fields = array(
            "declared_weight" => array(
                "amount" => $parcel_weight,
                "unit" => $parcel_weight_unit
            ),
            "sender" => array(
                "company_name" => $sender['company_name'],
                "country_code" => 'PL', //X only available in PL
                'email' => $sender['email'],
                'first_name' => $sender['firstname'],
                'last_name' => $sender['lastname'],
                'phone' => $sender['phone'],

            ),
            "recipient" => array(
                "company_name" => $receiver['company_name'],
                "country_code" => $iso_code_receiver,
                'email' => $receiver['email'],
                'first_name' => $receiver['firstname'],
                'last_name' => $receiver['lastname'],
                'phone' => $receiver['phone'] ? $receiver['phone'] : $receiver['phone_mobile'],
            ),
            "service" => "Standard",

            "declared_value" => array(
                "currency" => $currency,
                "amount" => $amountTotal
            ),

            'reference_id' => $sender['customer_reference'],
        );

        $fields['declared_dimensions'] = array(
            'height' => Tools::getValue('parcel_height'),
            'length' => Tools::getValue('parcel_length'),
            'unit' => Tools::getValue('parcel_size_unit'),
            'width' => Tools::getValue('parcel_width')
        );

        if ($receiver['parcel_locker']) {
            $fields['recipient']['pop'] = array(
                'id' => $receiver_pop_id,
                'size' => $parcel_size
            );
        } else {
            $fields['recipient']['address'] = array(
                'zip_code' => $receiver['postcode'],
                'building_number' => $receiver['building_no'],
                'city' => $receiver['city'],
                'flat_number' => $receiver['flat_no'],
                'street' => $receiver['street'],
            );
        }
        if (isset($sender_pop_id)) {
            $fields['sender']['pop'] = array(
                'id'=> $sender_pop_id,
                'size' => $parcel_size
            );
        } else {
            $fields['sender']['address'] = array(
                'zip_code' => $sender['postcode'],
                'building_number' => $sender['building_no'],
                'city' => $sender['city'],
                'flat_number' => $sender['flat_no'],
                'street' => $sender['street'],
            );
        }
        if (Tools::getValue('parcel_insurance')) {
            $fields["insurance"] = array(
                "currency" => $currency,
                "amount" => Tools::getValue('parcel_insurance_amount')
            );
        }
        $path = "/shipments";

        $response = $this->makeCurl($path, $fields, 'POST');

        if (is_array($response) || !$response) {
            return $this->validateErrors($response);
        }

        $response = $this->getShipment($response->id);

        if (InpostModel::savePackageCrossBorder(
            $response,
            Tools::getValue('id_order'),
            $receiver['country'],
            $sizesInCm,
            $receiver['id_customer'],
            $dispatch_points_id
        ))
        {
            return $response;
        }
        else
        {
            return ['error' => 1, 0 => 'Unexpected database error'];
        }
    }

    public function getAddressFormat($country_code)
    {
        $path = "/address-formats?";
        $fields = [
            'countries_codes' => $country_code
        ];

        return $this->makeCurl($path.http_build_query($fields));
    }

    /**
     * @param $pop_id
     * @param $for = recipient or sender
     * @param $iso_code
     * @return mixed
     */
    public function getPopsInCountry($for, $iso_code)
    {
        $path = "/users/me/pops?";
        $fields = [
            'request.available_for' => $for,
            'request.country_code' => $iso_code
        ];
        return $this->makeCurl($path.http_build_query($fields), [], 'GET');
    }

    public function userPops()
    {
        $path = "/users/me/pops";
        return $this->makeCurl($path, [], 'GET');
    }

    public function getShipment($id)
    {
        $path = "/shipments/{$id}";
        return $this->makeCurl($path, [], 'GET');
    }

    private function validateErrors($response)
    {
        $inpost = Module::getInstanceByName('inpost');

        $errors = ['error' => 1];

        foreach ($response as $error) {
            if ($error->message == 'WeightNotDefined') {
                $errors[] = $inpost->l('Parcel weight not defined', self::FILE);
            }
            if ($error->message == 'InvalidHeight') {
                $errors[] = $inpost->l('Invalid parcel height', self::FILE);
            }
            if ($error->message == 'InvalidWidth') {
                $errors[] = $inpost->l('Invalid parcel width', self::FILE);
            }
            if ($error->message == 'InvalidLength') {
                $errors[] = $inpost->l('Invalid parcel length', self::FILE);
            }
            if ($error->message == 'XBorderV1.InvalidDispatchPointStatus') {
                $errors[] = $inpost->l('Dispatch point has a wrong status', self::FILE);
            }
            if ($error->message == 'XBorderV1.RecipientZipCodeIsInvalid') {
                $errors[] = $inpost->l('Recipient zip code is invalid', self::FILE);
            }
            if ($error->message == 'PlInPostV1.CanNotCreateDispatchOrder') {
                $errors[] = $error->data[0]->value;
            }
            if ($error->message == 'RecipientPhoneIsEmpty') {
                $errors[] = $inpost->l('Recipient phone number is empty');
            }
            if ($error->message == 'RecipientPopNotFound') {
                $errors[] = $inpost->l('Receipent parcel locker not found');
            }
            if ($error->message == 'XBorderV1.DispatchPointIdIsEmpty') {
                $errors[] = $inpost->l('Dispatch Point Id is empty');
            }
            if ($error->message == 'XBorderV1.IncorrectDimensions') {
                $errors[] = $inpost->l('Incorrect Dimensions');
            }
            if ($error->message == 'XBorderV1.RecipientBuildingNumberIsEmpty') {
                $errors[] = $inpost->l('Receiver Building number is required', 'inpostconnector');
            }
        }

        if (!isset($errors[0])) {
            $errors[] = $inpost->l('Unexpected Error '. $response[0]->message);
        }

        return $errors;
    }

    public function getLabelPdf($id)
    {
        $path = "/shipments/{$id}/pdf-labels";

        return $this->makeCurl($path, [], 'GET');
    }
    public function createSticker($label, $parcel_no)
    {

        if ($label[0]->pdf_url !== null) {
            $response = Tools::file_get_contents($label[0]->pdf_url);
            $filename = _PS_MODULE_DIR_.'inpost/pdf/'.$parcel_no.'.pdf';
            return file_put_contents($filename, $response);
        }
    }

    public function generateManifest($packages_ids)
    {
        $fPackages = array();
        foreach ($packages_ids as $package) {
            $fPackages[] = array(
                'id' => $package
            );
        }

        $path = "/manifests";
        $fields = array(
            'shipments' =>   $fPackages

        );

        $response =  $this->makeCurl($path, $fields, 'POST');

        if ($response->pdf_url !== null) {
            $id_courier = $response->id;
            $response = Tools::file_get_contents($response->pdf_url);

            $filename = _PS_MODULE_DIR_.'inpost/pdf/'.$id_courier.'_manifest.pdf';
            $a =  file_put_contents($filename, $response);
            if ($a) {
                return $filename;
            }
        }
        return false;
    }

    public function carrierPickups($dispatch_point_id, $parcelsIds)
    {
        if (Tools::getValue('date_from')) {
            $date_from = date(DATE_ATOM, strtotime(Tools::getValue('date_from').' '.Tools::getValue('hour_from')));
            $date_to = date(DATE_ATOM, strtotime(Tools::getValue('date_from').' '.Tools::getValue('hours_to')));
        }
        $parcelsIdsCross = array();
        foreach ($parcelsIds as $parcelId) {
            $parcelsIdsCross[] = array(
                'id' => $parcelId
            );
        }
        $dispatch_x_id = Db::getInstance()->getValue('SELECT x_border_id FROM '._DB_PREFIX_.'inpost_dispatch_points
                                                        WHERE id ='.$dispatch_point_id);
        $path = "/carrier-pickups";
        $fields = array(
            'comment' => Tools::getValue('comments'),
            'reference' => Tools::getValue('reference'),
            'dispatch_point_id' => $dispatch_x_id,
            'dispatch_date' => [
                'from' => isset($date_from) ? $date_from : '',
                'to' => isset($date_to) ? $date_to : ''
            ],
            'shipments' =>
                $parcelsIdsCross

        );

        $response =  $this->makeCurl($path, $fields, 'POST');

        if (is_array($response)) {
            return $this->validateErrors($response);
        }

        return $response;

    }

    public function getUserDispatchPoints()
    {
        $path = "/users/me/dispatch-points";

        return $this->makeCurl($path, [], 'GET');
    }

    public static function getTokenFromConfiguration()
    {
        $token = DB::getInstance()->executeS('SELECT value, date_upd FROM '._DB_PREFIX_.'configuration
                                                WHERE `name` = "INPOST_TOKEN_X_BORDER"');
        if ($token) {
            if (date('U') > date('U', strtotime($token[0]['date_upd']. '+1 hour'))) {
                return false;
            }

            return unserialize($token[0]['value']);
        }


        return false;
    }

    public function getCarrierPickupsData($id)
    {
        if (!$id) {
            return false;
        }
        $path = "/carrier-pickups/{$id}";

        return $this->makeCurl($path, [], 'GET');

    }

    public function getPop($id)
    {
        $path = "/pops/{$id}";

        return $this->makeCurl($path, [], 'GET');
    }

}
