<?php
/**
 * 2007-2021 PrestaShop
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Academic Free License (AFL 3.0)
 * that is bundled with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://opensource.org/licenses/afl-3.0.php
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@prestashop.com so we can send you a copy immediately.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade PrestaShop to newer
 * versions in the future. If you wish to customize PrestaShop for your
 * needs please refer to http://www.prestashop.com for more information.
 *
 * @author    PrestaShop SA <contact@prestashop.com>
 * @copyright 2007-2021 PrestaShop SA
 * @license   http://opensource.org/licenses/afl-3.0.php  Academic Free License
 *           (AFL 3.0) International Registered Trademark & Property of
 *           PrestaShop SA
 */

// @codingStandardsIgnoreStart
/* @noinspection PhpMultipleClassDeclarationsInspection */
/* @noinspection PhpDeprecationInspection */
// @codingStandardsIgnoreEnd


if (!defined('_PS_VERSION_')) {
    exit;
}

if (!defined('_PS_USE_SSL_')) {
    define('_PS_USE_SSL_', (bool)Configuration::get('PS_SSL_ENABLED_EVERYWHERE', null, null, null, false));
}

require_once __DIR__ . '/vendor/autoload.php';

/**
 * Addon Payments module.
 *
 * @property string                name
 * @property string                displayName
 * @property string                description
 * @property string                tab
 * @property string                version
 * @property string                author
 * @property array                 controllers
 * @property string                confirmUninstall
 * @property bool                  bootstrap
 * @property \Context|\ContextCore context
 */
class addonpayments extends PaymentModule
{
    use Prestashop\Module\AddonPayments\Helpers\SecurityTrait;

    public const TOKEN_VALIDITY = 'ADDONPAYMENTS_TOKEN_VALIDITY';

    public const PS_OS_EASYPAYMENTGATEWAY_PENDING = 'PS_OS_EASYPAYMENTGATEWAY_PENDING';

    public const PS_OS_EASYPAYMENTGATEWAY_PROCESSING = 'PS_OS_EASYPAYMENTGATEWAY_PROCESSING';

    public const PS_OS_EASYPAYMENTGATEWAY_PENDING_CONFIRMATION = 'PS_OS_EASYPAYMENTGATEWAY_PENDING_CONFIRMATION';

    public const PS_OS_EASYPAYMENTGATEWAY_REBATE = 'PS_OS_EASYPAYMENTGATEWAY_REBATE';

    public const PAYMENT_STATUS_KEY = 'payment';

    public const PAYMENT_MESSAGE_KEY = 'message';

    public const PAYMENT_TRANSACTION_KEY = 'transaction';

    public const PAYMENT_STATUS_SUCCESS = 0;

    public const PAYMENT_STATUS_FAILED = 1;

    public const PAYMENT_STATUS_CANCELLED = 2;

    public const PAYMENT_STATUS_AWAITING = 3;

    public const PAYMENT_STATUS_UNKNOWN = 4;

    public const BNPL_NAME = 'quix';

    /**
     * Time span in milliseconds until the authorization token is expired.
     */
    public const AUTH_TOKEN_VALIDITY_THRESHOLD = 15 * 60 * 1000;

    public const REQUIRED_PHP_EXTENSIONS = [
        'curl',
        'iconv',
        'json',
        'mbstring',
        'openssl',
        'simplexml',
    ];

    public const HOOK_LIST = [
        'moduleRoutes',
        'paymentOptions',
        'actionFrontControllerSetMedia',
        'actionAdminControllerSetMedia',
        'actionProductCancel',
        'actionOrderStatusUpdate',
        'displayPayment',
        'displayPaymentReturn',
        'displayAdminOrderLeft',
        'displayAdminOrderMain',
        'displayAdminOrderTop',
        'displayAdminOrder',
        'displayMyAccountBlock',
        'displayCustomerAccount',
        'displayWrapperTop',
        'displayCaptureLink',
        'displayPaymentTop',
        'actionOrderSlipAdd',
        'displayProductPriceBlock',
        'displayReassurance',
        'displayExpressCheckout',
        'displayProductButtons',
        'displayBeforeShoppingCartBlock',
        'displayShoppingCart',
        'displayBackofficeOrderActions'
    ];

    public const HOOK_LIST_177 = [
        'actionGetAdminOrderButtons'
    ];

    public const REFUND_SELECTOR = '#desc-order-partial_refund';

    protected $config_form = false;

    public function __construct()
    {
        $this->name = 'addonpayments';
        $this->displayName = $this->l('Addon Payments', 'addonpayments');
        $this->description = $this->l('Integrates multiple payment solutions through a single gateway', 'addonpayments');
        $this->tab = 'payments_gateways';
        $this->version = '1.4.0';
        $this->author = 'Comercia Global Payments';
        $this->controllers = ['validation', 'confirmation', 'vault', 'payment', 'callback'];

        /*
         * Set $this->bootstrap to true if your module is compliant with bootstrap (PrestaShop 1.6)
         */
        $this->bootstrap = true;

        parent::__construct();

        $this->confirmUninstall = $this->l('Are you sure you want to uninstall Addon Payments?', 'addonpayments');

        $this->ps_versions_compliancy = ['min' => '1.6', 'max' => _PS_VERSION_];

        // list of template(s) file that needs to be overridden
        $this->admin_tpl_overrides = [
            implode(DIRECTORY_SEPARATOR, ['override', 'controllers', 'admin', 'templates', 'orders', 'helpers', 'view', 'view.tpl']),
            implode(DIRECTORY_SEPARATOR, ['override', 'controllers', 'admin', 'templates', 'orders', '_documents.tpl']),
        ];
    }

    /**
     * Don't forget to create update methods if needed:
     * http://doc.prestashop.com/display/PS16/Enabling+the+Auto-Update
     */
    public function install(): bool
    {
        $format = $this->l("You have to enable the '%s' extension on your server to install this module", 'addonpayments');
        foreach (self::REQUIRED_PHP_EXTENSIONS as $extension) {
            if (false === extension_loaded($extension)) {
                $this->_errors[] = sprintf($format, $extension);

                return false;
            }
        }

        if (false === extension_loaded('bcmath') && false === extension_loaded('gmp')) {
            $this->_errors[] = sprintf(
                $this->l('This module needs one of the following PHP extensions installed and active on your web server: %s or %s. %s In case you need help with this issue, please contact your Prestashop integrator.', 'addonpayments'),
                '<strong>BCMath</strong>',
                '<strong>GMP</strong>',
                '<br />'
            );

            return false;
        }

        $iso_code = Country::getIsoById(
            Configuration::get('PS_COUNTRY_DEFAULT')
        );

        if (FALSE === !empty($this->limited_countries) && in_array(
                $iso_code,
                $this->limited_countries,
                TRUE
            )) {
            $this->_errors[] = $this->l(
                'This module is not available in your country',
                'addonpayments'
            );

            return FALSE;
        }

        $addonPaymentsConfig = new Prestashop\Module\AddonPayments\AddonPaymentsConfig($this);
        $addonPaymentsConfig->install();

        $rebate_status = Configuration::get( 'PS_CHECKOUT_STATE_PARTIAL_REFUND' );

        if ( ! empty( $rebate_status ) ) {
            Configuration::updateValue( self::PS_OS_EASYPAYMENTGATEWAY_REBATE, $rebate_status );
        }

        include __DIR__ . '/sql/install.php';

        $addAdminTplOverrides = $this->_addAdminTplOverrides();

        $install = parent::install()
            && $this->installOrderStatuses()
            && $addAdminTplOverrides;

        // @TODO Register hooks per PS version.
        foreach (self::HOOK_LIST as $hook) {
            $install = $install && $this->registerHook($hook);
        }

        if (\Prestashop\Module\AddonPayments\AddonPaymentsTools::is177()) {
            foreach (self::HOOK_LIST_177 as $hook) {
                $install = $install && $this->registerHook($hook);
            }
        }

        return $install && $this->installTabs();
    }

    /**
     * Create new order status
     *
     * @return bool
     */
    public function installOrderStatuses(): bool
    {
        try {
            $statuses = json_decode(
                Tools::file_get_contents('file://' . $this->local_path . '/data/statuses.json'),
                true
            );

            if (empty($statuses) || JSON_ERROR_NONE !== json_last_error()) {
                return false;
            }

            $languages = array_column(Language::getLanguages(), 'id_lang', 'iso_code');

            foreach ($statuses as $key => $value) {
                $orderState = new OrderState();
                $orderStateId = Configuration::get($key);

                if (!empty($orderStateId)) {
                    $orderState = new OrderState($orderStateId);
                }else {
                    $image = $value['image'];
                    unset($value['image']);
                    foreach ($value as $prop => $val) {
                        // This will be set later.
                        if ('name' === $prop) {
                            continue;
                        }
                        $orderState->{$prop} = $val;
                    }

                    // Set name using available language identifier by matching his ISO-2 code.
                    foreach ($value['name'] as $iso_code => $val) {
                        if (!array_key_exists($iso_code, $languages)) {
                            continue;
                        }

                        $orderState->name[$languages[$iso_code]] = $val;
                    }

                    if ($orderState->save()) {
                        $root = _PS_ROOT_DIR_;
                        copy("{$this->local_path}views/img/$image", "$root/img/os/$orderState->id.gif");
                    }
                }

                Configuration::updateValue($key, $orderState->id);
            }

            return true;
        } catch (Exception $e) {
            PrestaShopLogger::addLog($e->getMessage(), 3, $e->getCode(), $this->name);

            return false;
        }
    }

    /**
     * Install the tabs for the back office
     */
    private function installTabs(): bool
    {
        $tabs = json_decode(Tools::file_get_contents('file://' . $this->local_path . '/data/tabs.json'), true);

        if (empty($tabs) || JSON_ERROR_NONE !== json_last_error()) {
            return false;
        }

        $languages = array_column(Language::getLanguages(), 'id_lang', 'iso_code');
        $result = true;

        foreach ($tabs as $class => $tab) {
            $tabId = Tab::getIdFromClassName($class);
            $newTab = new Tab();

            if (false !== $tabId) {
                $newTab = new Tab($tabId);
            }

            $newTab->module = $this->name;
            $newTab->class_name = $class;
            $newTab->position = $tab['position'];
            $newTab->active = $tab['active'];
            $parentId = Tab::getIdFromClassName((string)$tab['parent']);

            if (empty($parentId)) {
                $parentId = -1;
            }

            $newTab->id_parent = $parentId;
            $default_language = 'en';

            // Set name using available language identifier by matching his ISO-2 code.
            foreach ($languages as $iso_code => $id_language) {

                if(isset($tab['name'][$iso_code])) {
                    $translated_name = $tab['name'][$iso_code];
                }else {
                    $translated_name = $tab['name'][$default_language];
                }

                $newTab->name[$id_language] = $translated_name;
            }

            $result &= $newTab->save();
        }

        return $result;
    }

    /**
     * Uninstall moule
     *
     * @return bool
     */
    public function uninstall(): bool
    {
        $addonPaymentsConfig = new Prestashop\Module\AddonPayments\AddonPaymentsConfig($this);
        $addonPaymentsConfig->uninstall();

        include __DIR__ . '/sql/uninstall.php';

        $uninstall = parent::uninstall();

        // @TODO Register hooks per PS version.
        foreach (self::HOOK_LIST as $hook) {
            $uninstall = $uninstall && $this->unregisterHook($hook);
        }

        $removeAdminTplOverrides = $this->_removeAdminTplOverrides();

        return $uninstall && $this->uninstallTabs() && $removeAdminTplOverrides;
    }

    /**
     * Uninstall the tabs for the back office
     */
    private function uninstallTabs(): bool
    {
        try {
            $tabs = json_decode(Tools::file_get_contents('file://' . $this->local_path . '/data/tabs.json'), true);
            $return = true;
            foreach (array_keys($tabs) as $class) {
                $tabId = Tab::getIdFromClassName($class);
                if (false === $tabId) {
                    continue;
                }

                $return &= (new Tab($tabId))->delete();
            }

            return $return;
        } catch (Exception $e) {
            PrestaShopLogger::addLog($e->getMessage(), 3, $e->getCode(), $this->name);

            return false;
        }
    }

    /**
     * Load the configuration form
     */
    public function getContent(): string
    {
        $form = new Prestashop\Module\AddonPayments\Form\ConfigurationForm($this);
        $tplVars = [
            'submitted'         => false,
            'show_status_panel' => false,
            'encryption_key'    => '',
            'docs_link'         => sprintf(
                "%smodules/%s/docs/%s.pdf",
                $this->context->link->getBaseLink(),
                $this->name,
                $this->context->language->iso_code
            ),
            'back_office'       => (Configuration::get(Prestashop\Module\AddonPayments\AddonPaymentsConfig::LIVE_MODE)
                ? ComerciaGlobalPayments\AddonPayments\SDK\Api\ApiClientInterface::BACKOFFICE_LIVE
                : ComerciaGlobalPayments\AddonPayments\SDK\Api\ApiClientInterface::BACKOFFICE_STAGING),
        ];

        /*
         * If values have been submitted in the form, process.
         */
        if (true === $form->postProcess()) {
            $tplVars['submitted'] = true;
        }

        $printKey = (false === (bool)Configuration::get(Prestashop\Module\AddonPayments\AddonPaymentsConfig::PRINTED_KEY));
        $tplVars += [
            'print_key' => $printKey,
        ];

        if (true === $printKey) {
            $tplVars['encryption_key'] = self::getEncryptionKey();
        }

        $tplVars['configuration_form'] = $form->render();

        if (false !== Configuration::get(Prestashop\Module\AddonPayments\AddonPaymentsConfig::MERCHANT_KEY)) {
            $hcWebApi = Prestashop\Module\AddonPayments\Services\ApiFactory::hcWebApi();
            $hcJsLibrary = Prestashop\Module\AddonPayments\Services\ApiFactory::hcJsLibrary();
            $tplVars['status_panel'] = [
                'web_api'  => [
                    'status'   => $hcWebApi,
                    'text'     => $this->l('Web API', 'addonpayments'),
                    'selector' => $hcWebApi ? 'available' : 'unavailable',
                    'icon'     => $hcWebApi ? 'bolt' : 'exclamation',
                    'hint'     => $hcWebApi ? $this->l('Working', 'addonpayments') : $this->l('Not working', 'addonpayments'),
                ],
                'renderer' => [
                    'status'   => $hcJsLibrary,
                    'text'     => $this->l('Payment form', 'addonpayments'),
                    'selector' => $hcJsLibrary ? 'available' : 'unavailable',
                    'icon'     => $hcJsLibrary ? 'bolt' : 'exclamation',
                    'hint'     => $hcJsLibrary ? $this->l('Working', 'addonpayments') : $this->l('Not working', 'addonpayments'),
                ],
            ];
            $tplVars['show_status_panel'] = true;
        }

        $this->context->smarty->assign($tplVars);

        return $this->display(__DIR__, 'views/templates/admin/module.tpl');
    }

    /**
     * @return void
     */
    public function hookModuleRoutes(): void
    {
        require_once __DIR__ . '/vendor/autoload.php';
    }

    /**
     * Set JS/CSS assets for certain controllers.
     *
     * @throws \PrestaShop\PrestaShop\Core\Localization\Exception\LocalizationException
     * @throws \Exception
     */
    public function hookActionFrontControllerSetMedia(): void
    {
        $controller = Tools::getValue('controller');

        if (!in_array($controller, ['order', 'payment', 'cart', 'product'])) {
            return;
        }

        $isLive = (bool)Configuration::get(Prestashop\Module\AddonPayments\AddonPaymentsConfig::LIVE_MODE);
        $path = $this->_path;
        $endpoints =  ComerciaGlobalPayments\AddonPayments\SDK\Api\EPGJs::getEndpoints($isLive);

        $commonVars = [
            'controller' => $controller,
            'language' => [
                'iso_code' => $this->context->language->iso_code,
                'locale' => \Prestashop\Module\AddonPayments\AddonPaymentsTools::getLocale($this->context),
            ],
            'currency' => [
                'specifications' => $this->preparePriceSpecifications($this->context),
                'iso_code' => $this->context->currency->iso_code,
            ],
            'banner' => [
                'product' => Configuration::get(Prestashop\Module\AddonPayments\AddonPaymentsConfig::FINANCING_OPTIONS) ?: Prestashop\Module\AddonPayments\AddonPaymentsConfig::FINANCING_DEFAULT_OPTION,
                'styleColor' => Configuration::get(Prestashop\Module\AddonPayments\AddonPaymentsConfig::BANNER_STYLE_COLOR) ?: '#34AEEB',
                'styleVariant' => Configuration::get(Prestashop\Module\AddonPayments\AddonPaymentsConfig::BANNER_STYLE_VARIANT),
                'styleBranding' => Configuration::get(Prestashop\Module\AddonPayments\AddonPaymentsConfig::BANNER_STYLE_BRANDING),
                'position' => Configuration::get(Prestashop\Module\AddonPayments\AddonPaymentsConfig::BANNER_POSITION)
            ]
        ];

        if (self::is17()) {
            $path = "modules/$this->name/";
        }

        $this->registerStylesheet(
            $path."views/css/front.css",
            "{$this->name}_css",
            ['priority' => 201]
        );

        if (in_array($controller, ['order', 'payment'])) {

            $this->registerJavascript(
               $endpoints['render'],
                'epgjs',
                ['priority' => 200, 'server' => 'remote']
            );

            if (!self::is17()) {
                $this->registerStylesheet(
                    $path."views/css/front-1.6.css",
                    "{$this->name}_16_css",
                    ['priority' => 201]
                );
            }

            $langcode = $this->context->language->iso_code;

            $jsVars = [
                'style' => Configuration::get(Prestashop\Module\AddonPayments\AddonPaymentsConfig::EPG_STYLE),
                'is17' => self::is17(),
                'langcode' => $langcode,
                'translations' => [
                    'unknownError'        => $this->l('An unexpected error occurred and your action cannot be performed. Please try reloading the page and if the problem persists contact us.', 'addonpayments'),
                    'authorizationFailed' => $this->l('Could not complete the authorization request for the selected payment method. Please, try selecting  another and if the problem persists contact us.', 'addonpayments'),
                    'registrationFailed'  => $this->l('An error occurred while registering the selected payment method. This is an error but you can complete the purchase nonetheless', 'addonpayments'),
                    'registrationSuccess' => $this->l('Payment method registered', 'addonpayments'),
                ],
                'i18n' => [
                    $langcode => Prestashop\Module\AddonPayments\Services\ApiFactory::getI18n($langcode),
                ],
                'cart' => [
                    'amount' => $this->context->cart->getOrderTotal(),
                ],
            ];

            Media::addJsDef([
                 $this->name => array_merge($jsVars, $commonVars)
            ]);

            $this->registerJavascript(
                $path."views/js/all-paysol.js",
                __CLASS__ . '_js',
                ['priority' => 201]
            );
        }

        $controllers =  ['product', 'cart'];
        if (!self::is17()) {
            $controllers[] = 'order';
        }

        if(in_array($controller, $controllers)) {

            $customerId = \Prestashop\Module\AddonPayments\Services\ApiFactory::getCustomerIdFromContext($this->context);
            $token = $this->getToken($customerId);

            if($controller === 'product') {
                $idProduct = Tools::getValue('id_product');
                $idProductAttribute =  Tools::getValue('id_product_attribute');
                $amount = Product::getPriceStatic($idProduct, true, $idProductAttribute, 2);
            }else {
                $amount = $this->context->cart->getOrderTotal();
            }

            $jsVars = [
                'baseUrl' => $endpoints['base'],
                'authUrl' => $this->context->link->getModuleLink($this->name, 'authorize', [
                    'action' => 'banner'
                ]),
                'authToken' => $token,
                'clientId' => $customerId,
                'amount' => $amount,
            ];

             Media::addJsDef([
                 $this->name => array_merge($jsVars, $commonVars)
             ]);

             $this->registerJavascript(
              $endpoints['nemuru-widget'],
                'epgjs-nemuru-widget',
                ['priority' => 200, 'server' => 'remote']
            );

            $this->registerJavascript(
                $path."views/js/front.js",
                __CLASS__ . '_front_js',
                ['priority' => 210]
            );
        }
    }

    /**
     * Set JS/CSS assets for certain admin controllers.
     */
    public function hookActionAdminControllerSetMedia(): void
    {
        $controller = Tools::getValue('controller');
        $order = new Order((int)Tools::getValue('id_order'));

        if ($controller === 'AdminOrders' && $order->module === $this->name) {
            $transactions = Transactions::getRefundableByOrder($order->id);

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

            $paymentSolution = reset($transactions)->paymentSolution;
            $isLive = (bool)Configuration::get(\Prestashop\Module\AddonPayments\AddonPaymentsConfig::LIVE_MODE);
            $endpoints = ComerciaGlobalPayments\AddonPayments\SDK\Api\EPGJs::getEndpoints($isLive);

            $callback = base64_encode(
                $this->getAdminLink(
                    'AdminOrders',
                    ['id_order' => $order->id, 'vieworder' => 1]
                )
            );

            Media::addJsDef([
                $this->name => [
                    'partialRefundLiteral' => $this->l('Refund on Addonpayments'),
                    'paymentSolution' => $paymentSolution,
                    'ajaxHandler' => $this->context->link->getAdminLink('AdminQuixRefund'),
                    'base_url' => $endpoints['base'],
                    'employee' => $this->context->employee->id,
                    'customer' => $this->context->customer->id,
                    'id_order' => $order->id,
                    'callback' => $callback,
                    'is_177' => \Prestashop\Module\AddonPayments\AddonPaymentsTools::is177(),
                    'currency_specifications' => $this->preparePriceSpecifications($this->context),
                ],
            ]);


            $this->context->controller->addJS( $endpoints['nemuru-widget'] );
            $this->context->controller->addJS($this->_path."views/js/refund.js");
        }

        if($controller === 'AdminModules' && Tools::getValue('configure') === $this->name ) {
            $this->context->controller->addCSS($this->_path.'views/css/admin.css');
            $this->context->controller->addJS($this->_path."views/js/admin.js");

            $addonpayments_config = new Prestashop\Module\AddonPayments\AddonPaymentsConfig($this);

            Media::addJsDef([
                'default_configuration' => $addonpayments_config->getDefaultPaymentConfig(),
            ]);
        }
    }

    /**
     * BC method to register javascript for current controller.
     */
    public function registerJavascript($uri, $id = null, array $options = []): void
    {
        if (!self::is17()) {
            $this->context->controller->addJS($uri);
            return;
        }

        if (null === $id) {
            $id = sha1($uri);
        }

        $this->context->controller->registerJavascript($id, $uri, $options);
    }

    /**
     * BC method to register stylesheets for current controller.
     */
    public function registerStylesheet($uri, $id = null, array $options = []): void
    {
        if (!self::is17()) {
            $this->context->controller->addCSS($uri);
            return;
        }

        if (null === $id) {
            $id = sha1($uri);
        }

        $this->context->controller->registerStylesheet($id, $uri, $options);
    }

    /**
     * Check if current PS >= 1.7
     * @deprecated
     * @todo remove
     *
     */
    public static function is17(): bool
    {
        return 0 === strpos(_PS_VERSION_, '1.7');
    }

    /**
     * Display the payment options for PS 1.6
     *
     * @return string
     *
     * @throws \SmartyException
     */
    public function hookDisplayPayment(): string
    {
        $params = [
            'cart' => $this->context->cart,
        ];
        $options = $this->hookPaymentOptions($params);
        $options = array_map(
            function ($option) {
                /* @var \Prestashop\Module\AddonPayments\Decorators\LegacyPaymentOption $option */
                return [
                    'text' => $option->getCallToActionText(),
                    'additional_information' => $option->getAdditionalInformation(),
                    'option' => $option->getModuleName(),
                    'paymentLogo' => $option->getLogo(),
                    'link' => $this->context->link->getModuleLink(
                        $this->name,
                        'payment',
                        [
                            'cart_id' => $this->context->cart->id,
                            'secure_key' => $this->context->cart->secure_key,
                            'option' => base64_encode($option->getModuleName()),
                        ],
                        _PS_USE_SSL_
                    ),
                ];
            },
            $options
        );
        $this->smarty->assign('payment_options', $options);

        return $this->display(__FILE__, 'views/templates/hook/payment.tpl');
    }

    /**
     * Return payment options available for PS 1.7+
     *
     * @param array Hook parameters
     *
     * @return \PrestaShop\PrestaShop\Core\Payment\PaymentOption[]|null
     *
     * @throws \SmartyException
     */
    public function hookPaymentOptions($params): ?array
    {
        if (!$this->active || !$this->checkCurrency($params['cart'])) {
            return null;
        }

        return (new Prestashop\Module\AddonPayments\Services\PaymentOptionsFactory($this))->getOptions();
    }

    /**
     * Hook for 1.6 confirm-order
     *
     * @param $params
     *
     * @return string
     */
    public function hookDisplayPaymentReturn($params): string
    {
        if (false === $this->active) {
            return '';
        }

        if(self::is17()) {
            return '';
        }

        $idOrder = Tools::getValue('id_order');
        $order = new Order($idOrder);
        $shipping = $order->getShipping();
        $shippingName = reset($shipping)['carrier_name'];

        $this->context->smarty->assign(
            [
                'order'           => $order,
                'price'           => Tools::ps_round($order->getTotalProductsWithTaxes(), _PS_PRICE_DISPLAY_PRECISION_) . $this->context->currency->sign,
                'reference_order' => $order->reference,
                'email'           => $this->context->customer->email,
                'payment_method' => $order->payment,
                'shipping_method' => $shippingName,
                'is_guest' => $this->context->customer->is_guest
            ]
        );

        return $this->context->smarty->fetch("{$this->local_path}views/templates/hook/payment-return.tpl");
    }

    /*
     * Show payment errors on PS 1.6
     */
    public function hookDisplayPaymentTop() {
        if(self::is17()) {
            return '';
        }
        return $this->hookDisplayWrapperTop();
    }

    /**
     * hookDisplayProductPriceBlock - Product page
     * Below price
     *
     * @param $params
     *
     * @return false|string|void
     */
    public function hookDisplayProductPriceBlock($params) {
        if($this->context->controller instanceof ProductController && 'price' === $params['type'] && !isset($params['from'])) {
            $price = self::is17() ? $params["product"]["price_amount"] : $params["product"]->price;
            $script = "<script>
                var addonpaymentsAmountUpdate = ".$price."
            </script>";

            if (1 != Configuration::get(Prestashop\Module\AddonPayments\AddonPaymentsConfig::BANNER_POSITION)) {
                return $script;
            }
            return '<div id="addon-payments-widget">'.$script.'</div>';
        }
    }

    /**
     * hookDisplayReassurance - Product page (1.7)
     *
     * @param $params
     *
     * @return false|string|void
     */
    public function hookDisplayReassurance($params) {
         if(2 != Configuration::get(Prestashop\Module\AddonPayments\AddonPaymentsConfig::BANNER_POSITION)) {
            return false;
        }

        if ($this->context->controller instanceof ProductController) {
            return '<div id="addon-payments-widget"></div>';
        }
    }

    /**
     * hookDisplayExpressCheckout - Cart page (1.7)
     *
     * @return string
     * @throws \Exception
     */
    public function hookDisplayExpressCheckout() {
        return '<div id="addon-payments-widget">
            <script>
                var addonpaymentsAmountUpdate = '.$this->context->cart->getOrderTotal().'
            </script>
        </div>';
    }

    /**
     * Product page (1.6) - Below add to cart
     * Deprecated on 1.7
     *
     * @param $params
     * @return string|void
     */
    public function hookDisplayProductButtons($params)
    {
        if (self::is17()) {
            return;
        }

        return '<div id="addon-payments-widget"></div>';
    }

    /**
     * Cart page (1.6)
     *
     * @param $params
     * @return string
     */
    public function hookDisplayBeforeShoppingCartBlock($params)
    {
        return '<div id="addon-payments-widget"></div>';
    }

    /**
     * Cart page (1.6). Call on ajax update cart
     *
     * @param $params
     * @return string
     */
    public function hookDisplayShoppingCart($params)
    {
        if ($this->context->controller instanceof CartController === false || self::is17()) {
            return '';
        }

        return "<script> var addonpaymentsAmountUpdate = ".$params["total_price"]."</script>";
    }

    /**
     * Shows a panel containing transactions generated by the order.
     *
     * PS 1.7.7
     */
    public function hookDisplayAdminOrderMain($context)
    {
        $order = new Order($context['id_order']);

         if (
            Tools::getValue('controller') === 'AdminOrders'
            && $order->module === $this->name
        ) {

             [$order, $transactions] = $this->_getTransactionsByOrderId($context['id_order']);

             $this->context->smarty->assign(
                 [
                     'order' => $order,
                     'transactions' => $transactions,
                 ]
             );

             return $this->context->smarty->fetch("{$this->local_path}views/templates/hook/display-admin-order-main.tpl");
         }
    }

    /**
     * Shows a panel containing transactions generated by the order.
     */
    public function hookDisplayAdminOrderLeft($context)
    {
        [$order, $transactions] = $this->_getTransactionsByOrderId($context['id_order']);

        if (
            Tools::getValue('controller') === 'AdminOrders'
            && $order->module === $this->name
        ) {

            $this->context->smarty->assign(
                [
                    'order' => $order,
                    'transactions' => $transactions,
                ]
            );

            return $this->context->smarty->fetch(
                "{$this->local_path}views/templates/hook/display-admin-order-left.tpl"
            );
        }
    }

    /**
     * Display notifications on admin Order on PS < 1.7.7
     *
     * @param $params
     *
     * @return void
     */
    public function hookDisplayAdminOrder($params)
    {
         if (\Prestashop\Module\AddonPayments\AddonPaymentsTools::is177()) {
            return false;
        }

        if (session_status() == PHP_SESSION_NONE) {
            session_start();
        }

        return $this->hookDisplayAdminOrderTop($params);
    }

    /**
     * Display notifications on admin Order on PS > 1.7.7
     *
     * @param $params
     * @return false|void
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    public function hookDisplayAdminOrderTop($params)
    {
        if(Tools::getValue('controller') !== 'AdminOrders') {
            return false;
        }

        $order = new Order($params['id_order']);

        if($order->module !== $this->name) {
            return false;
        }

        if (session_status() == PHP_SESSION_NONE) {
            session_start();
        }

        $session_refund = 'addonpayments_refund_status_'. $params['id_order'];

        if(!isset($_SESSION[$session_refund])) {
            return false;
        }

        $alertType = $_SESSION[$session_refund]['error'] ? 'danger': 'info';
        $button = '<button type="button" class="close" data-dismiss="alert" aria-label="Close">
                <span aria-hidden="true"><i class="material-icons">close</i></span>
            </button>';

         if (version_compare(_PS_VERSION_, '1.7.7', '<')) {
             $button = '<button type="button" class="close" data-dismiss="alert">×</button>';
         }

        $alert = '<div class="alert alert-'. $alertType .' d-print-none addonpayments-alert" role="alert">' .
            $button .
             '<div class="alert-text">
                <p>'. $_SESSION[$session_refund]['message'] .'</p>
             </div>
          </div>';

        unset($_SESSION[$session_refund]);

        return $alert;
    }

    /**
     * Add quix refund button on PS < 1.7.7
     *
     * @param $params
     *
     * @return false|string
     * @throws \SmartyException
     */
    public function hookDisplayBackofficeOrderActions($params){
//        if (\Prestashop\Module\AddonPayments\AddonPaymentsTools::is177()) {
//            return '<div id="epgjs-cashier-div"></div>';
//        }

        $order = new Order($params['id_order']);

        if ($order->module !== $this->name) {
            return '';
        }

        $transactions = Transactions::getRefundableByOrder($params['id_order']);

        if(empty($transactions)) {
            return '';
        }

        $paymentSolution = reset($transactions)->paymentSolution;

        if (('nemuru' === $paymentSolution || self::BNPL_NAME === $paymentSolution)
            && ($order->current_state === Configuration::get('PS_OS_PAYMENT')
                || $order->current_state === Configuration::get(self::PS_OS_EASYPAYMENTGATEWAY_REBATE))
        ) {

            $this->context->smarty->assign(
                [
                    'is_177' => \Prestashop\Module\AddonPayments\AddonPaymentsTools::is177(
                    ),
                ]
            );

            return $this->context->smarty->fetch(
                "{$this->local_path}views/templates/hook/display-backoffice-order-actions.tpl"
            );

        }

        return '';
    }

    /**
     * Add buttons to main buttons bar
     * PS: 1.7.7
     *
     * @param array $params
     *
     * @return void
     */
    public function hookActionGetAdminOrderButtons(array $params) {
        $order = new Order($params['id_order']);
        if ($order->module !== $this->name) {
            return;
        }

        $transactions = Transactions::getRefundableByOrder($params['id_order']);

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

        $paymentSolution = reset($transactions)->paymentSolution;

        if ( ('nemuru' === $paymentSolution || self::BNPL_NAME === $paymentSolution)
            && ($order->current_state === Configuration::get('PS_OS_PAYMENT')
                || $order->current_state === Configuration::get(self::PS_OS_EASYPAYMENTGATEWAY_REBATE))

        ) {
            /** @var \PrestaShopBundle\Controller\Admin\Sell\Order\ActionsBarButtonsCollection $bar */
            $bar = $params['actions_bar_buttons_collection'];

            $bar->add(
                new \PrestaShopBundle\Controller\Admin\Sell\Order\ActionsBarButton(
                    'btn-secondary',
                    ['href' => '#refundForm', 'id' => 'desc-order-quix_refund'],
                    $this->l('Refund on Quix', 'addonpayments')
                )
            );
        }
    }

    /**
     * @param $cart
     *
     * @return bool
     */
    public function checkCurrency($cart): bool
    {
        $currency_order = new Currency($cart->id_currency);
        $currencies_module = $this->getCurrency($cart->id_currency);
        if (is_array($currencies_module)) {
            foreach ($currencies_module as $currency_module) {
                if ((int)$currency_order->id === (int)$currency_module['id_currency']) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Generates a link to admin controller.
     *
     * Acts as proxy with BC between PS 1.6 and 1.7+.
     */
    public function getAdminLink(string $controller, array $params = [], array $sfRouteParams = []): string
    {
        if (self::is17()) {
            return $this->context->link->getAdminLink($controller, true, $sfRouteParams, $params);
        }

        $queryString = http_build_query($params);

        return $this->context->link->getAdminLink($controller) . '&' . $queryString;
    }

    /**
     * Display "Payment methods" link under "My account" block.
     *
     * @throws \SmartyException
     */
    public function hookDisplayMyAccountBlock()
    {
        return $this->displayVaultLink('my-account-block');
    }

    /**
     * Do render "Payment methods" link.
     *
     * @param string $template the link template to use
     *
     * @return false|string|null
     *
     * @throws \SmartyException
     */
    private function displayVaultLink(string $template)
    {
        if (!$this->active) {
            return null;
        }

        $this->context->smarty->assign(
            [
                'is_17'          => self::is17(),
                'my_account_url' => [
                    'id'    => 'vault-link',
                    'title' => $this->l('Payment methods', 'addonpayments'),
                    'url'   => $this->context->link->getModuleLink($this->name, 'vault'),
                ],
            ]
        );

        return $this->context->smarty->fetch("{$this->local_path}views/templates/hook/$template.tpl");
    }

    /**
     * Display "Payment methods" link on "My account" page content.
     *
     * @throws \SmartyException
     */
    public function hookDisplayCustomerAccount()
    {
        return $this->displayVaultLink('customer-account');
    }

    /**
     * Displays a message for the user if the payment failed.
     *
     * Process payment failure redirection, by default the module will
     * redirect to the checkout page with a query string like:
     *  ?payment=error => when an error occurs
     *  ?payment=cancelled => when the payment is cancelled by user
     * Then apropiate message is shown to the user. This is done this way
     * because there is no hook to subscribe for the checkout page, neither
     * can send a message back since the controller is PS core.
     */
    public function hookDisplayWrapperTop()
    {
        $status = Tools::getValue(self::PAYMENT_STATUS_KEY);

        if (empty($status)) {
            return null;
        }

        $message = Tools::getValue(self::PAYMENT_MESSAGE_KEY, null);
        $message = base64_decode($message);

        if (empty($message)) {
            $message = $this->l('The payment failed, please try again.', 'addonpayments');
        }

        $this->context->smarty->assign(
            [
                'message' => $message,
            ]
        );

        return $this->context->smarty->fetch("{$this->local_path}views/templates/hook/wrapper-top.tpl");
    }

    public function hookActionProductCancel(array $context = []): void
    {
        try {
            if (!$this->active) {
                // Just return here since this not actually wrong.
                return;
            }

            // PS > 1.7.7
            if(isset($context['action']) &&
               $context['action'] === PrestaShop\PrestaShop\Core\Domain\Order\CancellationActionType::PARTIAL_REFUND) {
                return;
            }

            $context = array_merge(Tools::getAllValues(), $context);

            /** @var \Order $order */
            $order = $context['order'];

            if (
                true === Tools::isSubmit('generateCreditSlip')
                || true === Tools::isSubmit('generateDiscount')
            ) {
                throw new Prestashop\Module\AddonPayments\Exception\NotReallyAnException(
                    "The refund for detail {$context['id_order_detail']} on order $order->reference is being flagged for credit slip or discount voucher"
                );
            }

            $transactions = Transactions::getRefundableByOrder($order->id);
            $paymentSolution = reset($transactions)->paymentSolution;

            if(self::BNPL_NAME === $paymentSolution || 'nemuru' === $paymentSolution) {
                throw new Prestashop\Module\AddonPayments\Exception\NotReallyAnException(
                    "$order->reference: Orders placed with Quix are not eligible for standard refunds"
                );
            }

            (new Prestashop\Module\AddonPayments\Operations\ProductCancel($this->context, $this))(
                $order,
                $context['id_order_detail'],
                $context['cancelQuantity']
            );
        } catch (Prestashop\Module\AddonPayments\Exception\NotReallyAnException $e) {
            // This is not an error just a form of black-box control flow.
            PrestaShopLogger::addLog($e->getMessage());
        } catch (Exception $e) {
            // Any other exception needs to be logged.
            PrestaShopLogger::addLog($e->getMessage(), 3, $e->getCode(), 'Order', $context['id_order']);
        }
    }

    /**
     * Reacts to order status change.
     *
     * @param array $context Contains the following keys:
     *                      - newOrderStatus: OrderState object with the order new status.
     *                      - id_order: The order id.
     */
    public function hookActionOrderStatusUpdate(array $context = []): void
    {
        // Used as semaphore to avoid evaluate hook if the order is being
        // processed.
        $semaphore = null;

        try {
            if (!$this->active) {
                return;
            }

            // If the controller is confirmation, the order state change
            // was issued by the gateway so no further action needs to be taken
            if ($this->context->controller instanceof AddonpaymentsConfirmationModuleFrontController) {
                return;
            }

            $order = new Order($context['id_order']);
            $semaphore = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $order->reference;
            // Check if the semaphore is set and is not older than 1 minute
            if (
                file_exists($semaphore)
                && stat($semaphore)['mtime'] > time() - 60
            ) {
                return;
            }

            touch($semaphore);
            // @TODO Use chain of responsibility pattern.
            /** @var \OrderState $newOrderStatus */
            $newOrderStatus = $context['newOrderStatus'];
            $pendingStateId = (int)Configuration::get(self::PS_OS_EASYPAYMENTGATEWAY_PENDING, null, null, null, 0);
            $refundStateId = (int)Configuration::get('PS_OS_REFUND', null, null, null, 0);
            $canceledStateId = (int)Configuration::get('PS_OS_CANCELED', null, null, null, 0);
            $paymentStateId = (int)Configuration::get('PS_OS_PAYMENT', null, null, null, 0);

            if ($newOrderStatus->id === $canceledStateId && $pendingStateId === (int)$order->current_state) {
                (new Prestashop\Module\AddonPayments\Operations\OrderVoid($this->context, $this))($order);

                return;
            }

            if ($newOrderStatus->id === $refundStateId && $paymentStateId === (int)$order->current_state) {
                (new Prestashop\Module\AddonPayments\Operations\OrderRefund($this->context, $this))($order);

                return;
            }

            if ($newOrderStatus->id === $paymentStateId && $pendingStateId === (int)$order->current_state) {
                [$jokerOrder, $transactions] = $this->_getTransactionsByOrderId($context['id_order']);
                if (!$urls = array_column($transactions, 'capture_link')) {
                    throw new Exception("There are not urls available");
                }

                Tools::redirectAdmin(reset($urls));
            }
        } catch (Prestashop\Module\AddonPayments\Exception\NotReallyAnException $e) {
            // This is not an error just a form of black-box control flow.
            PrestaShopLogger::addLog($e->getMessage());
        } catch (Exception $e) {
            // Any other exception needs to be logged.
            PrestaShopLogger::addLog($e->getMessage(), 3, $e->getCode(), 'Order', $context['id_order']);
        } finally {
            // Always clear the semaphore file
            if (null !== $semaphore && file_exists($semaphore)) {
                unlink($semaphore);
            }
        }
    }

    /**
     * Partial refund
     *
     * @throws \PrestaShopDatabaseException
     * @throws \PrestaShopException
     */
    public function hookActionOrderSlipAdd($params)
    {
        if (Tools::isSubmit('partialRefundAddonpayments')) {
            $amount = 0;
            $originalAmount = 0;

            $params = array_merge(Tools::getAllValues(), $params);

            if (empty($params['productList'])) {
                return false;
            }
            foreach ($params['productList'] as $product) {
                $amount += \Tools::ps_round($product['amount'], _PS_PRICE_DISPLAY_PRECISION_);

                 if (false == empty($params['cancel_product'])){
                     $id_order_detail = $product['id_order_detail'];
                     $originalAmount += $params['cancel_product']['amount_'.$id_order_detail];
                 }
            }

            if (false == empty($params['partialRefundShippingCost'])) {
                $amount += $params['partialRefundShippingCost'];
            }

            // For prestashop version > 1.7.7
            if (false == empty($params['cancel_product'])) {
                $refundData = $params['cancel_product'];
                $amount += floatval(str_replace(',', '.', $refundData['shipping_amount']));
            }

            $amount -= $this->calculateDiscount($params);

            $response = (new Prestashop\Module\AddonPayments\Operations\OrderRefund($this->context, $this))($params['order'], $amount);

            if (session_status() == PHP_SESSION_NONE) {
                session_start();
            }

            if($response) {
                $errorMessage = $this->mapErrorMessage($response->message);

                $_SESSION['addonpayments_refund_status_' . $params['order']->id] = [
                    'error' => true,
                    'message' => $errorMessage['errorMessage'] ?? $errorMessage,
                    'id_order' => $params['order']->id,
                ];

            }else {
                if (version_compare(_PS_VERSION_, '1.7', '>=')) {
                    $currency = $this->context->currency->getSymbol();
                }else {
                    $currency = $this->context->currency->sign;
                }

                if($originalAmount > $amount) {
                    $message =sprintf(
                        $this->l('A partial refund has been issued: %s refunded instead of %s.'),
                        $amount . $currency,
                        $originalAmount . $currency
                    );
                }else {
                     $message =sprintf(
                        $this->l('A partial refund has been issued: %s refunded.'),
                        $amount . $currency
                    );
                }

                $this->context->controller->informations[] = $message;

                $_SESSION['addonpayments_refund_status_' . $params['order']->id] = [
                    'error' => false,
                    'message' => $message,
                    'id_order' => $params['order']->id,
                ];

            }
        }
    }

    /**
     * @param mixed $params
     *
     * @return float
     */
    public function calculateDiscount($params)
    {
        // $params differs according PS version
        $amount = 0;

        if (false == empty($params['refund_voucher_off'])) {
            if (false == empty($params['order_discount_price'])) {
                return floatval($params['order_discount_price']);
            }
        }

        if (false == empty($params['cancel_product']['voucher_refund_type'])) {
            if ($params['cancel_product']['voucher_refund_type'] == 1) {
                if ($params['order'] instanceof Order) {
                    return (float)$params['order']->total_discounts_tax_incl;
                }
            }
        }

        return $amount;
    }

    /**
     * Attach capture link to PENDING transactions.
     * @Deprecated
     */
    private function attachCaptureLink(Order $order, array $transactions): array
    {
        $pending = ComerciaGlobalPayments\AddonPayments\SDK\Response\OperationInterface::STATUS_PENDING;
        /** @var \OrderPayment[] $payments */
        $payments = OrderPayment::getByOrderReference($order->reference);
        $payments = array_filter(
            array_map(
                function ($payment) {
                    if ($payment->payment_method !== $this->name) {
                        return null;
                    }

                    return $payment->transaction_id;
                },
                $payments
            )
        );
        $redirect = base64_encode(
            $this->getAdminLink(
                'AdminOrders',
                ['id_order' => $order->id, 'vieworder' => null]
            )
        );
        foreach ($transactions as $delta => $transaction) {
            if (
                $pending !== $transaction['status']
                || in_array($transaction['payFrexTransactionId'], $payments, true)
            ) {
                continue;
            }

            $transactions[$delta]['capture_link'] = $this->getAdminLink(
                'AdminCaptureTransaction',
                ['transaction' => $transaction['id_transaction'], 'redirect' => $redirect]
            );
        }

        return $transactions;
    }

    /**
     * PrestaShop doesn't allow override admin templates inside module, so we override the prestashop template structure
     *
     * @return bool
     */
    public function _addAdminTplOverrides(): bool
    {
        $module_override_path = $this->getLocalPath() . DIRECTORY_SEPARATOR;
        $result = true;
        foreach ($this->admin_tpl_overrides as $admin_tpl_path) {
            $override_file_path = $module_override_path . $admin_tpl_path;
            $dest_override_file_path = _PS_ROOT_DIR_ . DIRECTORY_SEPARATOR . $admin_tpl_path;

            $path_info = pathinfo($dest_override_file_path);
            if (!file_exists($path_info['dirname'])) {
                mkdir($path_info['dirname'], 0777, true);
            }

            if (!file_exists($dest_override_file_path)) {
                touch($dest_override_file_path);
            }

            if (file_exists($override_file_path)) {
                if (!copy($override_file_path, $dest_override_file_path)) {
                    $result &= false;
                }
            } else {
                $result &= false;
            }
        }

        return $result;
    }

    /**
     * Remove override templates
     *
     * @return bool
     */
    private function _removeAdminTplOverrides(): bool
    {
        $module_override_path = $this->getLocalPath() . DIRECTORY_SEPARATOR;
        $result = true;
        foreach ($this->admin_tpl_overrides as $admin_tpl_path) {
            $dest_override_file_path = _PS_ROOT_DIR_ . DIRECTORY_SEPARATOR . $admin_tpl_path;
            if (file_exists($dest_override_file_path)) {
                if (!unlink($dest_override_file_path)) {
                    $result &= false;
                }
            }
        }
        return $result;
    }

    /**
     * Custom hook to display CAPTURE link on order status
     *
     * @param array $context Contains the following keys:
     *     - smarty: Template variables.
     *     - cookie: Web cookies.
     *     - cart: Order cart.
     *     - altern.
     *
     * @return string
     */
    public function hookDisplayCaptureLink($context): string
    {
        $id_order = Order::{self::is17() ? 'getIdByCartId' : 'getOrderByCartId'}($context['cart']->id);
        [$order, $transactions] = $this->_getTransactionsByOrderId($id_order);

        $this->context->smarty->assign(
            [
                'order'        => $order,
                'transactions' => $transactions,
            ]
        );

        return $this->context->smarty->fetch("{$this->local_path}views/templates/hook/display-capture-link.tpl");
    }

    /**
     * Function responsible for return order and transactions with id_order
     *
     * @param int $id_order As the name suggests the order id
     *
     * @return array Contains the order and the transactions
     */
    private function _getTransactionsByOrderId($id_order): array
    {
        $order = new Order($id_order);
        $transactions = Transactions::getByOrder($order->id);
        $transactions = $this->attachCaptureLink($order, $transactions);
        $transactions = $this->setDescriptionMessage($transactions);

        return [$order, $transactions];
    }

    private function setDescriptionMessage($transactions) {

        foreach ($transactions as &$transaction) {
            if($transaction['status'] === \ComerciaGlobalPayments\AddonPayments\SDK\Response\OperationInterface::STATUS_ERROR ||
            $transaction['status'] === \ComerciaGlobalPayments\AddonPayments\SDK\Response\OperationInterface::STATUS_FAIL ||
            $transaction['status'] === \ComerciaGlobalPayments\AddonPayments\SDK\Response\OperationInterface::STATUS_ERROR3DS
            ) {
                $message = self::mapErrorMessage($transaction['message']);

                if(isset($message['transactionDescription'])) {
                     $transaction['message'] = $message['transactionDescription'];
                }
            }
        }

        return $transactions;
    }

    /**
     * Prepare price specifications to display cldr prices in javascript
     * context.
     *
     * PS 1.7: AdminController.php:4807
     * PS 1.6: Tools.php:690
     *
     * @param Context $context
     *
     * @return array
     * @throws \PrestaShop\PrestaShop\Core\Localization\Exception\LocalizationException
     */
    private function preparePriceSpecifications(Context $context)
    {
        /* @var Currency */
        if(self::is17()) {
            $currency = $context->currency;
            /* @var PrestaShop\PrestaShop\Core\Localization\Specification\Price */
            $priceSpecification = $context->getCurrentLocale()
                                          ->getPriceSpecification( $currency->iso_code );
            if ( empty( $priceSpecification ) ) {
                return [];
            }

            return array_merge(
                [
                    'symbol' => $priceSpecification->getSymbolsByNumberingSystem(
                        PrestaShop\PrestaShop\Core\Localization\Locale::NUMBERING_SYSTEM_LATIN
                    )->toArray(),
                ],
                $priceSpecification->toArray()
            );
        }else {

            $format = $context->currency->format;
            $symbol = [];

            if ( ( $format == 2 ) && ( $context->language->is_rtl == 1 ) ) {
                $format = 4;
            }

            switch ($format) {
            /* X 0,000.00 */
                case 1:
                case 4:
                    $symbol = ['.', ','];
                    break;
                /* 0 000,00 X*/
                case 2:
                     $symbol = [',', ' '];
                    break;
                /* X 0.000,00 */
                case 3:
                     $symbol = [',', '.'];
                    break;
                /* X 0'000.00  Added for the switzerland currency */
                case 5:
                     $symbol = ['.', "'"];
                    break;
            }

            return [
                'symbol' => $symbol
            ];

        }
    }

//    /**
//     * Gets locale by version
//     *
//     * @return string
//     */
//    private function getLocale() {
//
//        if(self::is17()) {
//            $locale = $this->context->language->locale;
//        } else {
//            $canonicalLocale = Locale::canonicalize($this->context->language->language_code);
//            $locale = str_replace('_', '-', $canonicalLocale);
//        }
//
//        return $locale;
//    }

    /**
     * Get authorzation token
     *
     * @throws \Exception
     */
    private function getToken($customerId) {
        $token = (new Prestashop\Module\AddonPayments\Operations\Authorize())(
                $customerId,
                $this->context->currency->iso_code,
                $this->context->country->iso_code,
                !$this->context->customer->isLogged()
            );
        $tokenValidity = (time() * 1000) + Prestashop\Module\AddonPayments\Services\ApiFactory::getTokenValidityThreshold();

        return [
            'token' => $token,
            'tokenValidity' => $tokenValidity
        ];
    }

    /**
     * Return translated error message
     *
     * @param string $message
     *
     * @return string|array
     */
    public function mapErrorMessage(string $message)
    {
        $translated_message = "";
        $message = str_replace('"', '', $message);

        $data = [
            "Transaction has been DESISTED/CANCELED" => $this->l('Transaction has been CANCELED.', 'addonpayments'),
//            "Denied 'Auth' operation with code: 180 message: Tarjeta ajena al servicio o no compatible." => $this->l('Non-compliant or unsupported card.', 'addonpayments'),
            "pricing conditions are not allowed" => $this->l('The price conditions are not allowed, it is too low or too high.', 'addonpayments'),
            "/shipping/phone_number:The data must match the 'phone-number' format,/billing/phone_number:The data must match the 'phone-number' format" => $this->l('The phone number is invalid.', 'addonpayments'),
            "/shipping/phone_number:The data must match the 'phone-number' format" => $this->l('The shipping phone number is invalid.', 'addonpayments'),
            "/billing/phone_number:The data must match the 'phone-number' format" => $this->l('The billing phone number is invalid.', 'addonpayments'),
            "Transaction has been DENIED" => $this->l('Transaction has been DENIED. Please, try selecting another and if the problem persists contact us.', 'addonpayments' ),
            "Amount to refund exceed" => [
                'errorMessage' => $this->l('Transaction has failed. The refund amount must be less than or equal to the amount that has not yet been refunded.', 'addonpayments' ),
                'transactionDescription' => $this->l('Amount to refund exceed', 'Addonpayments')
            ],
            "Not authenticated" => $this->l('Not authenticated', 'addonpayments')
        ];

         $filteredData = array_filter($data, function ($key) use ($message) {
                return strpos($message, $key) !== FALSE;
            },ARRAY_FILTER_USE_KEY
        );

        if(!empty($filteredData)) {
            $translated_message = reset($filteredData);
        }

        return $translated_message;
    }
}
