<?php

/**
 * 2007-2019 PrestaShop SA and Contributors.
 *
 * 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:
 * https://opensource.org/licenses/AFL-3.0
 * 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-2019 PrestaShop SA and Contributors
 * @license   https://opensource.org/licenses/AFL-3.0  Academic Free License (AFL 3.0)
 * International Registered Trademark & Property of PrestaShop SA
 */
if (! defined('_PS_VERSION_')) {
    exit;
}

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

use PrestaShop\PrestaShop\Core\Domain\Order\CancellationActionType;
use PrestaShop\PrestaShop\Core\Payment\PaymentOption;
use Sibs\DB\SibsMigration;
use Sibs\DB\SibsSeeder;
use Sibs\Models\PrestashopConfiguration;
use Sibs\Models\PrestashopModule;
use Sibs\Models\SibsOrderRef;
use Sibs\Models\SibsOrderRefLog;
use Sibs\Models\SibsTerminal;
use Sibs\SibsBrowser;
use Sibs\SibsConstants;
use Sibs\SibsException;
use Sibs\SibsLogger;
use Sibs\SibsPaymentCore;
use Sibs\SibsUtils;
use Sibs\SibsWebhookDecryptor;

class Sibs extends PaymentModule
{
    /**
     * HTML.
     *
     * @var string
     */
    protected $html = '';

    /**
     * Payment Methods.
     *
     * @var array
     */
    public $payment_methods = [
        SibsConstants::PAYMENT_METHOD_CREDIT_CARD,
        SibsConstants::PAYMENT_METHOD_BLIK,
        SibsConstants::PAYMENT_METHOD_PAY_BY_LINK,
        SibsConstants::PAYMENT_METHOD_XPAY,
    ];

    /**
     * Payment Authorizations Mehtods.
     *
     * @var array
     */
    public $payment_authorizations_methods = [
        SibsConstants::PAYMENT_METHOD_CREDIT_CARD,
        SibsConstants::PAYMENT_METHOD_BLIK,
        SibsConstants::PAYMENT_METHOD_PAY_BY_LINK,
        SibsConstants::PAYMENT_METHOD_XPAY,
    ];

    /**
     * Card Payment Methods.
     *
     * @var array
     */
    public $card_payment_methods = [
        SibsConstants::PAYMENT_METHOD_CREDIT_CARD,
    ];

    /**
     * Fields Form.
     *
     * @var array
     */
    public $fields_form;

    /**
     * Constructor.
     */
    public function __construct()
    {
        $this->version                = SibsConstants::SIBS_PLUGIN_VESION;
        $this->name                   = SibsConstants::SIBS_PLUGIN_NAME;
        $this->tab                    = SibsConstants::SIBS_PLUGIN_TAB;
        $this->ps_versions_compliancy = SibsConstants::SIBS_PRESTASHOP_VERSION_COMPLIANCY;
        $this->author                 = SibsConstants::SIBS_PLUGIN_AUTHOR;
        $this->bootstrap              = SibsConstants::SIBS_PLUGIN_BOOTSTRAP;

        parent::__construct();

        $this->displayName      = SibsConstants::SIBS_DISPLAY_NAME;
        $this->description      = $this->l('Accepts payments by SIBS');
        $this->confirmUninstall = $this->l('Are you sure you want to delete your details?');

        if (! PrestashopModule::isPluginVersionUpdated($this->version)) {
            PrestashopModule::updatePluginVersion($this->version, $this->name);
        }
    }

    /**
     * Install.
     *
     * @return void
     */
    public function install()
    {
        SibsLogger::info('SIBS Install');

        try {
            if (! function_exists('curl_init')) {
                $errorMessage = $this->l('cURL is required to use this module. Please install the php extention cURL.');

                throw new SibsException($errorMessage);
            }

            SibsLogger::info('Validated cURL');

            $installResult = parent::install(); // This call enable function

            if (! $installResult) {
                $errorMessage = $this->l('There was an Error installing the module.');

                throw new SibsException($errorMessage);
            }

            SibsLogger::info('Validated Parent Install');

            $hooksResult = (
                $this->registerHook('header') &&
                $this->registerHook('displayAdminOrderMain') &&
                $this->registerHook('displayAdminOrderSide') &&
                $this->registerHook('displayFooter') &&
                $this->registerHook('paymentReturn') &&
                $this->registerHook('displayInvoice') &&
                $this->registerHook('paymentOptions') &&
                $this->registerHook('displayTop') &&
                $this->registerHook('moduleRoutes') &&
                $this->registerHook('actionEmailAddAfterContent') &&
                $this->registerHook('actionProductCancel') &&
                $this->registerHook('actionValidateCustomerAddressForm')
            );

            if (! $hooksResult) {
                $errorMessage = $this->l('There was an Error on register the module hooks.');

                throw new SibsException($errorMessage);
            }

            SibsLogger::info('Validated Register Hooks');

            $orderStatusResult = $this->addSibsOrderStatus();

            if (! $orderStatusResult) {
                $errorMessage = $this->l('There was an Error creating a custom order status.');

                throw new SibsException($errorMessage);
            }

            SibsLogger::info('Validated Order Status');

            $configurationDefault = $this->setConfigurations();

            if (! $configurationDefault) {
                $errorMessage = $this->l('There was an Error on setting the default configurations.');

                throw new SibsException($errorMessage);
            }

            SibsLogger::info('Validated Default Configurations');

            return true;
        } catch (SibsException $e) {
            $this->_errors[] = $e->getErrorMessage();
            SibsLogger::error($e->getMessage());

            return false;
        } catch (Exception $e) {
            $this->_errors[] = $e->getMessage();
            SibsLogger::error($e->getMessage());

            return false;
        }
    }

    /**
     * Uninstall.
     *
     * @return bool
     */
    public function uninstall()
    {
        SibsLogger::info('SIBS Uninstall');

        $deleteConfigurationResult = $this->deleteConfigurations();

        if (! $deleteConfigurationResult) {
            return false;
        }

        $unregisterHookResult = (
            $this->unregisterHook('header') &&
            $this->unregisterHook('displayAdminOrderMain') &&
            $this->unregisterHook('displayAdminOrderSide') &&
            $this->unregisterHook('displayFooter') &&
            $this->unregisterHook('paymentReturn') &&
            $this->unregisterHook('displayInvoice') &&
            $this->unregisterHook('paymentOptions') &&
            $this->unregisterHook('displayTop') &&
            $this->unregisterHook('moduleRoutes') &&
            $this->unregisterHook('actionEmailAddAfterContent') &&
            $this->unregisterHook('actionProductCancel')
        );

        if (! $unregisterHookResult) {
            return false;
        }

        $uninstallResult = parent::uninstall();

        if (! $uninstallResult) {
            return false;
        }

        return true;
    }

    /**
     * Enable.
     *
     * @return bool
     */
    public function enable($force_all = false)
    {
        SibsLogger::info('SIBS Enable');

        if (! parent::enable($force_all)) {
            return false;
        }

        try {
            $tablesResult = SibsMigration::execute();

            if (! $tablesResult) {
                $errorMessage = $this->l('There was an Error creating a custom table.');

                throw new SibsException($errorMessage);
            }

            SibsLogger::info('Validated Table Migrations');

            $seedsResult = SibsSeeder::execute();

            if (! $seedsResult) {
                $errorMessage = $this->l('There was an Error seeding a custom table.');

                throw new SibsException($errorMessage);
            }

            SibsLogger::info('Validated Table Seeders');

            return true;
        } catch (Exception $e) {
            $this->_errors[] = $e->getMessage();
            SibsLogger::error($e->getMessage());

            return false;
        }
    }

    /**
     * Disable.
     *
     * @return bool
     */
    public function disable($force_all = false)
    {
        SibsLogger::info('SIBS Disable');

        if (! parent::disable($force_all)) {
            return false;
        }

        // Perform additional operations on disabling the module

        return true;
    }

    /**
     * Set Configurations.
     *
     * @return bool
     */
    public function setConfigurations()
    {
        // default general setting.
        $configurationResult = (
            Configuration::updateValue('SIBS_POPUP', true) &&

            // UPDATE SIBS GENERALS
            Configuration::updateValue('SIBS_GENERAL_CLIENTID', '') &&
            Configuration::updateValue('SIBS_GENERAL_TERMINALID', '') &&
            Configuration::updateValue('SIBS_GENERAL_BEARER', '') &&
            Configuration::updateValue('SIBS_WEBHOOK_SECRET', '') &&
            Configuration::updateValue('SIBS_GENERAL_ENVIRONMENT', '') &&

            // UPDATE SIBS ACTIVE
            Configuration::updateValue('SIBS_CC_ACTIVE', '1') &&
            Configuration::updateValue('SIBS_BLIK_ACTIVE', '1') &&
            Configuration::updateValue('SIBS_PAY_BY_LINK_ACTIVE', '1') &&
            Configuration::updateValue('SIBS_XPAY_ACTIVE', '1') &&

            // UPDATE MODES
            Configuration::updateValue('SIBS_CC_MODE', SibsConstants::PAYMENT_MODE_DEBIT) &&
            Configuration::updateValue('SIBS_BLIK_MODE', SibsConstants::PAYMENT_MODE_DEBIT) &&
            Configuration::updateValue('SIBS_PAY_BY_LINK_MODE', SibsConstants::PAYMENT_MODE_PAY_BY_LINK) &&
            Configuration::updateValue('SIBS_XPAY_MODE', SibsConstants::PAYMENT_MODE_XPAY) &&
            Configuration::updateValue('SIBS_XPAY_MERCHANTID_DOMAIN_ASSOCIATION', '') &&

            // UPDATE SIBS SORT
            Configuration::updateValue('SIBS_CC_SORT', '1') &&
            Configuration::updateValue('SIBS_BLIK_SORT', '2') &&
            Configuration::updateValue('SIBS_PAY_BY_LINK_SORT', '3') &&
            Configuration::updateValue('SIBS_XPAY_SORT', '4') &&

            // UPDATE PAY BY LINK DATA
            Configuration::updateValue('SIBS_PAY_BY_LINK_EXPIRATION_PAYMENT_VALUE', '3') &&
            Configuration::updateValue('SIBS_PAY_BY_LINK_EXPIRATION_PAYMENT_TYPE', 'day') &&

            // UPDATE BLIK DATA
            Configuration::updateValue('SIBS_BLIK_NUMBER_OF_RETRIES_VALUE', '30') &&
            Configuration::updateValue('SIBS_BLIK_DELAY_BETWEEN_RETRIES_VALUE', '1') &&

            // UPDATE CARDS
            Configuration::updateValue('SIBS_CC_CARDS', '') &&

            // UPDATE CARD DATA
            Configuration::updateValue('SIBS_CC_ONECLICK', SibsConstants::SIBS_TOKEN_NONE)
        );

        return $configurationResult;
    }

    /**
     * Delete Configurations.
     *
     * @return bool
     */
    public function deleteConfigurations()
    {
        $deleteConfigurationResult = (
            Configuration::deleteByName('SIBS_POPUP') &&

            // DELETE SIBS GENERALS
            Configuration::deleteByName('SIBS_GENERAL_CLIENTID') &&
            Configuration::deleteByName('SIBS_GENERAL_TERMINALID') &&
            Configuration::deleteByName('SIBS_GENERAL_BEARER') &&
            Configuration::deleteByName('SIBS_WEBHOOK_SECRET') &&
            Configuration::deleteByName('SIBS_GENERAL_ENVIRONMENT') &&

            // DELETE SIBS ACTIVE
            Configuration::deleteByName('SIBS_CC_ACTIVE') &&
            Configuration::deleteByName('SIBS_BLIK_ACTIVE') &&
            Configuration::deleteByName('SIBS_PAY_BY_LINK_ACTIVE') &&
            Configuration::deleteByName('SIBS_XPAY_ACTIVE') &&

            // DELETE MODES
            Configuration::deleteByName('SIBS_CC_MODE') &&
            Configuration::deleteByName('SIBS_BLIK_MODE') &&
            Configuration::deleteByName('SIBS_PAY_BY_LINK_MODE') &&
            Configuration::deleteByName('SIBS_XPAY_MODE') &&

            // DELETE SIBS SORT
            Configuration::deleteByName('SIBS_CC_SORT') &&
            Configuration::deleteByName('SIBS_BLIK_SORT') &&
            Configuration::deleteByName('SIBS_PAY_BY_LINK_SORT') &&
            Configuration::deleteByName('SIBS_XPAY_SORT') &&
            Configuration::deleteByName('SIBS_XPAY_MERCHANTID_DOMAIN_ASSOCIATION') &&

            // DELETE PAY BY LINK DATA
            Configuration::deleteByName('SIBS_PAY_BY_LINK_EXPIRATION_PAYMENT_VALUE') &&
            Configuration::deleteByName('SIBS_PAY_BY_LINK_EXPIRATION_PAYMENT_TYPE') &&

            // DELETE BLIK DATA
            Configuration::deleteByName('SIBS_BLIK_NUMBER_OF_RETRIES_VALUE') &&
            Configuration::deleteByName('SIBS_BLIK_DELAY_BETWEEN_RETRIES_VALUE') &&

            // DELETE CARDS
            Configuration::deleteByName('SIBS_CC_CARDS') &&

            // DELETE CARD DATA
            Configuration::deleteByName('SIBS_CC_ONECLICK')
        );

        return $deleteConfigurationResult;
    }

    /**
     * Add SIBS Order Status.
     *
     * @return bool
     */
    public function addSibsOrderStatus()
    {
        try {
            $this->addOrUpdateOrderStatus([
                'config_key' => SibsConstants::ORDER_STATUS_SIBS_PENDING,
                'locale'     => SibsConstants::ORDER_STATUS_SIBS_PENDING_TRANSLATIONS,
                'send_email' => false,
                'color'      => SibsConstants::ORDER_STATUS_SIBS_PENDING_COLOR,
                'hidden'     => false,
                'delivery'   => false,
                'logable'    => true,
                'invoice'    => false,
                'paid'       => false,
            ]);

            $this->addOrUpdateOrderStatus([
                'config_key' => SibsConstants::ORDER_STATUS_SIBS_AUTHORIZED,
                'locale'     => SibsConstants::ORDER_STATUS_SIBS_AUTHORIZED_TRANSLATIONS,
                'send_email' => true,
                'color'      => SibsConstants::ORDER_STATUS_SIBS_AUTHORIZED_COLOR,
                'hidden'     => false,
                'delivery'   => false,
                'logable'    => true,
                'invoice'    => false,
                'paid'       => false,
            ]);

            $this->addOrUpdateOrderStatus([
                'config_key' => SibsConstants::ORDER_STATUS_SIBS_REFUND_PENDING,
                'locale'     => SibsConstants::ORDER_STATUS_SIBS_REFUND_PENDING_TRANSLATIONS,
                'send_email' => false,
                'color'      => SibsConstants::ORDER_STATUS_SIBS_REFUND_PENDING_COLOR,
                'hidden'     => false,
                'delivery'   => false,
                'logable'    => true,
                'invoice'    => false,
                'paid'       => false,
            ]);

            return true;
        } catch (SibsException $e) {
            SibsLogger::error($e->getErrorMessage());

            return false;
        }
    }

    /**
     * Add Or Update Order Status.
     *
     * @param array $params
     * @return void
     */
    public function addOrUpdateOrderStatus($params)
    {
        $configuration_status_id = PrestashopConfiguration::getConfigurationId($params);
        $order_state_id          = null;

        if (! empty($configuration_status_id)) {
            $statusConfiguration = new Configuration($configuration_status_id);
            $order_state_id      = $statusConfiguration->getFields()['value'] ?? null;
        }

        $isNewOrderState = empty($order_state_id);

        $orderState              = ($isNewOrderState) ? new OrderState() : new OrderState($order_state_id);
        $orderState->name        = [];
        $orderState->module_name = $this->name;
        $orderState->send_email  = $params['send_email'];
        $orderState->color       = $params['color'];
        $orderState->hidden      = $params['hidden'];
        $orderState->delivery    = $params['delivery'];
        $orderState->logable     = $params['logable'];
        $orderState->invoice     = $params['invoice'];
        $orderState->paid        = $params['paid'];

        foreach (Language::getLanguages() as $language) {
            $id_lang = $language['id_lang'];

            $language_iso_code = strtolower($language['iso_code']);
            $name              = isset($params['locale'][$language_iso_code]) ? $params['locale'][$language_iso_code] : $params['locale']['en'];

            $orderState->template[$id_lang] = 'payment';
            $orderState->name[$id_lang]     = $name;
        }

        $executedWithSuccess = ($isNewOrderState) ? $orderState->add() : $orderState->update();

        if ($executedWithSuccess) {
            $sibs_icon      = _PS_MODULE_DIR_ . $this->name . '/sibs_logo.png';
            $new_state_icon = _PS_IMG_DIR_ . "os/{$orderState->id}.gif";
            copy($sibs_icon, $new_state_icon);

            Configuration::updateValue($params['config_key'], (int) $orderState->id);
        } else {
            throw new SibsException('Error on create or update Order Status');
        }
    }

    /**
     * HOOK: Module Routes.
     *
     * @param array $params
     * @return array
     */
    public function hookModuleRoutes($params)
    {
        if (! $this->active) {
            return [];
        }

        // SibsLogger::warning("hookModuleRoutes: " . SibsLogger::prettify($params));

        return [
            'module-sibs-webhook' => [
                'rule'       => 'sibs/webhook',
                'keywords'   => [],
                'controller' => 'webhook',
                'params'     => [
                    'fc'     => 'module',
                    'module' => 'sibs',
                ],
            ],
            'module-sibs-oneclickPage'  => [
                'controller' => 'sibs/oneclickPage',
                'keywords'   => [],
                'params'     => [
                    'fc'     => 'module',
                    'module' => 'sibs',
                ],
            ],
            'module-sibs-oneclickTerms'  => [
                'controller' => 'sibs/oneclickTerms',
                'keywords'   => [],
                'params'     => [
                    'fc'     => 'module',
                    'module' => 'sibs',
                ],
            ],
        ];
    }

    /**
     * HOOK: Display Top.
     *
     * @param array $params
     * @return mixed
     */
    public function hookDisplayTop($params)
    {
        if (! $this->active) {
            return;
        }

        // SibsLogger::warning("hookDisplayTop: " . SibsLogger::prettify($params));

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

        if (! $sibs_error) {
            return false;
        }

        $this->context->smarty->assign([
            'error_message' => $sibs_error,
            'module'        => 'sibs',
        ]);

        SibsLogger::error("sibs_error: $sibs_error");

        return $this->display(__FILE__, 'error.tpl');
    }

    /**
     * HOOK: Header.
     *
     * @param array $params
     * @return void
     */
    public function hookHeader($params)
    {
        if (! $this->active) {
            return;
        }

        $this->context->controller->addJS('http://code.jquery.com/ui/1.13.2/jquery-ui.min.js');

        if (isset($this->context->controller->php_self) && $this->context->controller->php_self === 'order') {
            $this->context->controller->addCSS(($this->_path) . 'views/css/payment_options.css', 'all');
            $this->context->controller->addJS(($this->_path) . 'views/js/payment_options.js', 'all');
        }

        $this->context->controller->addJS(($this->_path) . 'views/js/jquery.steps.min.js', 'all');
        $this->context->controller->addJS(($this->_path) . 'views/js/sibs-payments.js', 'all');
        $this->context->controller->addJS(($this->_path) . 'views/js/sibs-setting.js', 'all');
    }

    /**
     * HOOK: Payment Options.
     *
     * @param array $params
     * @return array
     */
    public function hookPaymentOptions($params)
    {
        if (! $this->active) {
            return;
        }

        // SibsLogger::warning("hookPaymentOptions: " . SibsLogger::prettify($params));

        if (! $this->checkCurrency($params['cart'])) {
            return;
        }

        $paymentOptions = [];
        $paymentMethods = $this->getAvailablePaymentMethods();

        foreach ($paymentMethods as $paymentMethod) {
            switch ($paymentMethod) {
                case SibsConstants::PAYMENT_METHOD_CREDIT_CARD:
                    array_push($paymentOptions, $this->newCardPaymentOption($paymentMethod));

                    break;
                default:
                    array_push($paymentOptions, $this->newPaymentOption($paymentMethod));

                    break;
            }
        }

        return $paymentOptions;
    }

    /**
     * HOOK: Paymnt Return.
     *
     * @param array $params
     * @return mixed
     */
    public function hookPaymentReturn($params)
    {
        if (! $this->active) {
            return false;
        }

        // SibsLogger::warning("hookPaymentReturn: " . SibsLogger::prettify($params));

        $succesfulStates = [
            Configuration::get(SibsConstants::ORDER_STATUS_PAYMENT),
            Configuration::get(SibsConstants::ORDER_STATUS_SIBS_PENDING),
            Configuration::get(SibsConstants::ORDER_STATUS_SIBS_AUTHORIZED),
        ];

        $state = $params['order']->getCurrentState();
        SibsLogger::info("state: $state");

        $orderId = Tools::getValue('id_order');
        SibsLogger::info("orderId: $orderId");

        $order         = (array) $params['order'];
        $order_payment = $this->l($order['payment']);

        if (in_array($state, $succesfulStates)) {
            $sibsOrder = SibsOrderRef::getOrderSibs($orderId);

            switch ($sibsOrder['payment_method']) {
                case SibsConstants::PAYMENT_METHOD_CARD:
                case SibsConstants::PAYMENT_METHOD_TOKEN:
                case SibsConstants::PAYMENT_METHOD_CREDIT_CARD:
                    $image = 'views/img/card.png';

                    break;
                case SibsConstants::PAYMENT_METHOD_XPAY:
                    $image = 'views/img/google.svg';

                    break;
                case SibsConstants::PAYMENT_METHOD_BLIK:
                    $image = 'views/img/blik.png';

                    break;
                    // case SibsConstants::PAYMENT_METHOD_PAY_BY_LINK:
                case SibsConstants::PAYMENT_METHOD_PAY_BY_LINK_KEVIN:
                    $image = 'views/img/pay_by_link.png';

                    break;
                default:
                    $image = 'views/img/sibs_logo.png';
            }

            $message = $this->l('Thank you. Your order has been received and successfull paid with') . " $order_payment";
            $method  = $this->context->cookie->__get('sibs_paymentBrand');

            switch ($state) {
                case Configuration::get(SibsConstants::ORDER_STATUS_PAYMENT):
                case Configuration::get(SibsConstants::ORDER_STATUS_SIBS_AUTHORIZED):
                    $status   = $this->l('Success');
                    $template = 'order_successful';

                    break;
                case Configuration::get(SibsConstants::ORDER_STATUS_SIBS_PENDING):
                    $status   = $this->l('Pre-Authorization');
                    $template = 'order_pa';

                    break;
                default:
                    $status   = '';
                    $template = '';
            }

            SibsLogger::info("method: $method");
            SibsLogger::info("status: $status");
            SibsLogger::info("template: $template");

            $vars = [
                'shop_name' => $this->context->shop->name,
                'status'    => 'ok',
                'image'     => Tools::getShopDomain(true, true) . __PS_BASE_URI__ . "modules/sibs/$image",
                'message'   => $message,
            ];
        } else {
            $vars = ['status' => 'nok'];
        }

        $this->context->smarty->assign($vars);
        $this->context->cookie->__unset('sibs_paymentBrand');

        return $this->display(__FILE__, 'payment_return.tpl');
    }

    /**
     * HOOK ACTION: Email Add After Content.
     *
     * @param array $params
     * @return void
     */
    public function hookActionEmailAddAfterContent($params)
    {
        if (! $this->active) {
            return;
        }

        // SibsLogger::warning("hookActionEmailAddAfterContent: " . SibsLogger::prettify($params));

        $content = '';

        if (in_array($params['template'], ['order_conf', 'order_pa'])) {
            $cookie         = (array) $params['cookie'];
            $cookie_content = $cookie["\0*\0_content"];

            SibsLogger::info("template: {$params['template']}");
            SibsLogger::info('cookie inside template: <pre>' . SibsLogger::prettify($cookie_content) . '</pre>');

            if ($cookie_content['sibs_paymentBrand']) {
                $orderMethod = $cookie_content['sibs_paymentBrand'];
                SibsLogger::info("orderMethod: $orderMethod");

                if (in_array($orderMethod, [SibsConstants::PAYMENT_METHOD_BLIK, SibsConstants::PAYMENT_METHOD_PAY_BY_LINK])) {
                    if ($orderMethod == SibsConstants::PAYMENT_METHOD_BLIK) {
                        $translatedText = $this->l('Your order will be processed after successful payment in the BLIK app');
                    } elseif ($orderMethod == SibsConstants::PAYMENT_METHOD_PAY_BY_LINK) {
                        $translatedText = $this->l('Your order will be processed after successful payment in the PBL app');
                    }

                    // PT: A sua encomenda será processada após pagamento com sucesso na app PBL
                    // EN: Your order will be processed after successful payment in the PBL app
                    $count = 0;
                    SibsLogger::info('found: ' . substr_count($params['template_html'], '{SHOP_NAME}!'));

                    $tempContent             = "<br><span style=\"font-weight:500;font-size:12px;\">{$translatedText}</span>";
                    $params['template_html'] = str_replace(
                        '{shop_name}!',
                        "{shop_name}!$tempContent",
                        $params['template_html'],
                        $count
                    );

                    SibsLogger::info("replaced: $count");
                }
            }
        }

        $params['template_html'] = str_replace('{payment}', "{payment}$content", $params['template_html']);
    }

    /**
     * HOOK: Display Invoice.
     *
     * @param array $params
     * @return mixed
     */
    public function hookDisplayInvoice($params)
    {
        if (! $this->active) {
            return;
        }

        // SibsLogger::warning("hookDisplayInvoice: " . SibsLogger::prettify($params));

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

        $success_message = '';
        $error_message   = '';

        $continueCheck = $this->checkCookieSibsStatus($success_message, $error_message, 'capture');

        if ($continueCheck) {
            $continueCheck = $this->checkCookieSibsStatus($success_message, $error_message, 'refund');
        }

        if ($continueCheck) {
            $continueCheck = $this->checkCookieSibsStatus($success_message, $error_message, 'cancel');
        }

        if ($continueCheck) {
            $continueCheck = $this->checkCookieSibsStatus($success_message, $error_message, 'update_order');
        }

        if ($continueCheck) {
            $continueCheck = $this->checkCookieSibsStatus($success_message, null, 'new_order');
        }

        $this->context->smarty->assign([
            'module'         => (is_object($order) && isset($order->module) ? $order->module : null),
            'successMessage' => $success_message,
            'errorMessage'   => $error_message,
        ]);

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

    /**
     * HOOK: Display Admin Order Main.
     *
     * @param array $params
     * @return mixed
     */
    public function hookDisplayAdminOrderMain(array $params)
    {
        $sibsOrder = SibsOrderRefLog::getOrderSibsLogger($params['id_order']);

        $this->context->smarty->assign([
            'order_id'  => $params['id_order'],
            'sibsOrder' => $sibsOrder,
        ]);

        return $this->context->smarty->fetch($this->getLocalPath() . 'views/templates/hook/displayAdminOrderLeft.tpl');
    }

    /**
     * HOOK: Display Footer.
     *
     * @param array $params
     * @return mixed
     */
    public function hookDisplayFooter($params)
    {
        $this->context->smarty->assign([
            'url_module'  => _MODULE_DIR_,
            'url_site'    => __PS_BASE_URI__,
        ]);

        return $this->context->smarty->fetch($this->getLocalPath() . 'views/templates/hook/displayFooter.tpl');
    }

    /**
     * HOOK: Display Admin Order Side.
     *
     * @param array $params
     * @return mixed
     */
    public function hookDisplayAdminOrderSide($params)
    {
        if (! $this->active) {
            return;
        }

        // SibsLogger::warning('displayAdminOrderSide: ' . SibsLogger::prettify($params));

        $orderID   = Tools::getValue('id_order');
        $sibsOrder = SibsOrderRef::getOrderSibs($orderID);

        SibsLogger::info("hookDisplayAdminOrderSide: $orderID");
        SibsLogger::info("orderID: $orderID");
        SibsLogger::info('sibsOrder: ' . SibsLogger::prettify($sibsOrder));

        if ($sibsOrder) {
            // sibs order status
            if (Tools::isSubmit('sibsOrderStatus')) {
                SibsLogger::info('sibsOrderStatus.....');
                $this->sibsOrderStatus($sibsOrder);
            }

            // sibs capture
            if (Tools::isSubmit('sibsCapture')) {
                SibsLogger::info('sibsCapture.....');
                $this->sibsCapture($sibsOrder);
            }

            // sibs refund
            if (Tools::isSubmit('sibsRefund')) {
                SibsLogger::info('sibsRefund.....');
                $this->sibsRefund($sibsOrder);
            }

            $this->sibsMakeContext($sibsOrder);
        }

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

    /**
     * HOOK ACTION: Validate Customer Address Form.
     *
     * @param array $params
     * @return void
     */
    public function hookActionValidateCustomerAddressForm($params)
    {
        if (! $this->active) {
            return;
        }

        $customer        = new Customer($params['cart']->id_customer);
        $customerAddress = ['customer' => $customer, 'cart' => $params['cart']];

        $module = Module::getInstanceByName('sibs');

        $form       = $params['form'];
        $id_address = $params['cart']->id_address_invoice
            ?: ($params['cart']->id_address_delivery ?: null);

        $address     = $this->getAddress($id_address);
        $postcode    = $address->postcode ?? null;
        $countryCode = $form->getField('id_country')->getValue();

        if (!empty($postcode) && is_numeric($countryCode)) {
            $validator_country = new Country($countryCode);
            $validator         = $validator_country->checkZipCode($postcode);

            if ($validator === false) {
                $form->addError(
                    $form->translator->trans(
                        'Invalid postcode - should look like "%zipcode%"',
                        ['%zipcode%' => $validator_country->zip_code_format],
                        'Shop.Forms.Errors'
                    )
                );
            }
        }

        $address1_chars = strlen((string) $form->getValue('address1'));
        $address2_chars = strlen((string) $form->getValue('address2'));
        $total_char     = $address1_chars + $address2_chars;

        SibsLogger::warning('total_char: ' . $total_char);

        if ($total_char > 70) {
            $address1 = $form->getField('address1');
            $address2 = $form->getField('address2');

            $address1->addError($module->l('ERROR_CHARS'));
            $address2->addError($module->l('ERROR_CHARS'));
        }

        SibsLogger::warning('hookActionValidateCustomerAddressForm: ' . json_encode($customerAddress));
    }

    /**
     * HOOK ACTION: Product Cancel.
     *
     * @param array $params
     * @return void
     */
    public function hookActionProductCancel($params)
    {
        if (! $this->active) {
            return;
        }

        // SibsLogger::warning("hookActionProductCancel: " . SibsLogger::prettify($params));

        switch ($params['action']) {
            case CancellationActionType::STANDARD_REFUND:
                SibsLogger::info('STANDARD_REFUND');

                break;
            case CancellationActionType::RETURN_PRODUCT:
                SibsLogger::info('RETURN_PRODUCT');

                break;
            case CancellationActionType::PARTIAL_REFUND:
                SibsLogger::info('PARTIAL_REFUND');
                $getOrderSibs = SibsOrderRef::getOrderSibs($params['order']->id);
                $sibsOrder    = new Order($params['order']->id);

                SibsLogger::warning('hookActionProductCancel: sibsOrder ' . json_encode($sibsOrder, true));

                $this->sibsRefundParcial($getOrderSibs, $sibsOrder, $params);

                break;
            case CancellationActionType::CANCEL_PRODUCT:
                SibsLogger::info('CANCEL_PRODUCT');

                break;
        }
    }

    /**
     * HOOK ACTION: Order Slip Add.
     *
     * @param array $params
     * @return void
     */
    public function hookActionOrderSlipAdd($params)
    {
        if (! $this->active) {
            return;
        }

        // SibsLogger::warning("actionOrderSlipAdd: " . SibsLogger::prettify($params));

        $order_slips = OrderSlip::getOrdersSlip((int) $params['order']->id_customer, (int) $params['order']->id);

        foreach ($order_slips as $order_slip_details) {
            $order_slip = new OrderSlip((int) $order_slip_details['id_order_slip']);
            /* Your actions. */
        }
    }

    /**
     * Get Address.
     *
     * @param array $address
     * @return Address|null
     */
    public function getAddress($address)
    {
        if (is_numeric($address)) {
            $address = new Address($address);
        }

        if ($address instanceof Address) {
            return $address;
        }

        return null;
    }

    /**
     * New Payment Option.
     *
     * @param string $paymentMethod
     * @return PaymentOption
     */
    public function newPaymentOption($paymentMethod)
    {
        $lowercasePaymentMethod = Tools::strtolower($paymentMethod);
        $paymentController      = $this->context->link->getModuleLink(
            $this->name,
            "payment{$lowercasePaymentMethod}",
            [],
            true
        );

        $logo     = "{$lowercasePaymentMethod}.png";
        $logoPath = Media::getMediaPath(_PS_MODULE_DIR_ . "{$this->name}/views/img/$logo");

        $newPaymentOption = new PaymentOption();
        $paymentForm      = $this->fetch('module:sibs/views/templates/hook/payment_options.tpl');
        $text             = $this->getPaymentDescription($paymentMethod);

        $newPaymentOption->setCallToActionText($text)
            ->setLogo($logoPath)
            ->setModuleName($this->name)
            ->setForm($paymentForm)
            ->setAction($paymentController);

        return $newPaymentOption;
    }

    /**
     * New Card Payment Option.
     *
     * @param string $paymentMethod
     * @return PaymentOption
     */
    public function newCardPaymentOption($paymentMethod)
    {
        $oneclick = Configuration::get('SIBS_CC_ONECLICK');

        $lowercasePaymentMethod = Tools::strtolower($paymentMethod);
        $paymentController      = $this->context->link->getModuleLink(
            $this->name,
            "payment{$lowercasePaymentMethod}",
            [],
            true
        );

        $newCardPaymentOption = new PaymentOption();

        $ccBrands = explode(',', Configuration::get("SIBS_{$paymentMethod}_CARDS"));

        if (! empty($ccBrands)) {
            $lowercaseCcBrand_0 = Tools::strtolower($ccBrands[0]);
            $logo               = "{$lowercaseCcBrand_0}.png";
            $logoPath           = Media::getMediaPath(_PS_MODULE_DIR_ . "{$this->name}/views/img/$logo");
            $text               = $this->getPaymentDescription($paymentMethod);

            $hiddenLogos = '';

            foreach ($ccBrands as $key => $ccBrand) {
                $lowercaseCcBrand = Tools::strtolower($ccBrand);
                $hiddenLogo       = "{$lowercaseCcBrand}.png";
                $hiddenLogoPath   = Media::getMediaPath(_PS_MODULE_DIR_ . "{$this->name}/views/img/$hiddenLogo");
                $hiddenLogos .= "<input type=\"hidden\" id=\"cc_brand_{$key}\" value=\"$hiddenLogoPath\">";
            }

            $newCardPaymentOption->setCallToActionText($text)
                ->setLogo($logoPath)
                ->setModuleName($this->name)
                ->setAdditionalInformation($hiddenLogos)
                ->setAction($paymentController);

            if ($this->context->customer->isLogged() && $oneclick === SibsConstants::SIBS_TOKEN_ONECLICK) {
                $oneclickPaymentForm = $this->getOneclickForm($paymentController);
                $newCardPaymentOption->setForm($oneclickPaymentForm);
            }
        }

        return $newCardPaymentOption;
    }

     /**
      * Get Oneclick PDF Terms By Language.
      *
      * @return string
      */
     public function getOneclickPDFTermsByLanguage()
     {
         // Update from: https://www.pay.sibs.com/eng/documentation/sibs-gateway-3/files/20220713_End%20customer%20regulations%20PL_KK_PS_PDF.pdf/
         // Update from: https://www.pay.sibs.com/eng/documentation/sibs-gateway-3/files/20220713_End%20customer%20regulations%20PL_KK_PS%20en-US_PDF.pdf/

         $iso_code = Context::getContext()->language->iso_code;

         switch($iso_code) {
             case 'pl':
             case 'en':
                 return "sibs_terms_and_conditions_{$iso_code}.pdf";

                 break;
             default:
                 return 'sibs_terms_and_conditions_en.pdf';
         }
     }

    /**
     * Get Oneclick Form.
     *
     * @param  $paymentController
     * @return string
     */
    public function getOneclickForm($paymentController)
    {
        $pdf        = $this->getOneclickPDFTermsByLanguage();
        $siteUrl    = str_replace('/shop', '', (Tools::getHttpHost(true) . __PS_BASE_URI__));
        $pdfMedia   = "modules/sibs/views/files/$pdf";
        $embedMedia = "{$siteUrl}{$pdfMedia}";

        $sibsTermsAndConditionsLabel   = $this->l('SIBS terms of service');
        $sibsTermsAndConditionsTagLink = '
            <div style="display:none" id="dialog" title="' . $this->l('OneClick Definition Page') . '">
                <p>' .
                    $this->l('If you activate OneClick, we will verify your card and you will see a transaction for 0 PLN on your account.') .
                    $this->l('Please note that your bank may require additional authorization.') .
                '</p>
                <p>' .
                    $this->l('With OneClick activated, we will not ask you to enter your card details for future payments.') .
                '</p>
            </div>
            <div style="display:none" id="dialog2" title="' . $this->l('SIBS terms of service') . '">
                <embed src="' . $embedMedia . '" frameborder="0" width="100%" style="float:left; position:relative; height:100%;">
            </div>
            <span onclick="$(\'#dialog2\').dialog({ height: 400, width:600});" id="cta-terms-and-conditions-sibs" 
                style="color:#24b9d7; text-decoration:none; cursor:pointer;">
                ' . $sibsTermsAndConditionsLabel . '
            </span>';

        $oneclickLabel   = $this->l('OneClick');
        $oneclickTagLink = '
            <span onclick="$(\'#dialog\').dialog({ height: 400, width:600});" id="cta-oneclick-sibs"
                style="color:#24b9d7; text-decoration:none; cursor:pointer;">
                ' . $oneclickLabel . '
            </span>';

        $customerAcceptorLabel = sprintf(
            $this->l('I agree to the %s and will adhere to them unconditionally for %s payment.'),
            $sibsTermsAndConditionsTagLink,
            $oneclickTagLink
        );

        $oneclickPaymentForm = '
            <form action="' . $paymentController . '" method="post" style="padding-bottom:10px">
                <div class="float-xs-left">
                    <span class="custom-checkbox">
                        <input type="checkbox" id="sibsCustomerAcceptor" name="sibsCustomerAcceptor" class="ps-shown-by-js">
                        <span><i class="material-icons rtl-no-flip checkbox-checked"></i></span>
                    </span>
                </div>
                <div class="condition-label">
                    <label class="js-terms" for="sibsCustomerAcceptor">
                        ' . $customerAcceptorLabel . '
                    </label>
                </div>
            </form>';

        return $oneclickPaymentForm;
    }

    /**
     * Get Terms and COnditioins Link.
     *
     * @return string
     */
    public function getTermsAndConditionsLink()
    {
        return $this->context->link->getModuleLink('sibs', 'oneclickTerms', [], true);
    }

    /**
     * Get Oneclick Link.
     *
     * @return string
     */
    public function getOneclickLink()
    {
        return $this->context->link->getModuleLink('sibs', 'oneclickPage', [], true);
    }

    /**
     * Check Cookie SIBS Status.
     *
     * @param string $success_message
     * @param string $error_message
     * @param string $status
     * @return bool
     */
    public function checkCookieSibsStatus(&$success_message, &$error_message, $status)
    {
        $cookieIsSet = $this->context->cookie->__isset("sibs_status_{$status}");

        if ($cookieIsSet) {
            if ($this->context->cookie->__get("sibs_status_{$status}")) {
                $success_message = $status;
            } else {
                $error_message = $status;
            }
        }

        $this->context->cookie->__unset("sibs_status_{$status}");

        return $cookieIsSet;
    }

    /**
     * Check Currency.
     *
     * @param Cart $cart
     * @return bool
     */
    public function checkCurrency($cart)
    {
        $currencyOrder   = new Currency($cart->id_currency);
        $currencyModules = $this->getCurrency($cart->id_currency);

        if (is_array($currencyModules)) {
            foreach ($currencyModules as $currencyModule) {
                if ($currencyOrder->id == $currencyModule['id_currency']) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Get Available Payment Methods.
     *
     * @return array
     */
    private function getAvailablePaymentMethods()
    {
        $paymentMethods = $this->payment_methods;
        $toSub          = null;

        //Acesso à db que corrige todos os estados pending (código 15)
        $toSub['template'] = 'order_pa';
        $toSub['name']     = 'Pagamento Pendente';

        $sortedPaymentMethods = [];
        foreach ($paymentMethods as $paymentMethod) {
            if (Configuration::get("SIBS_{$paymentMethod}_ACTIVE")) {
                if (in_array($paymentMethod, $this->card_payment_methods)) {
                    if (trim(Configuration::get("SIBS_{$paymentMethod}_CARDS"))) {
                        $sortedPaymentMethods[$paymentMethod] = Configuration::get("SIBS_{$paymentMethod}_SORT");
                    }
                } else {
                    $sortedPaymentMethods[$paymentMethod] = Configuration::get("SIBS_{$paymentMethod}_SORT");
                }
            }
        }

        $keys   = array_keys($sortedPaymentMethods);
        $values = array_values($sortedPaymentMethods);
        array_multisort($values, $keys);

        return $keys;
    }

    /**
     * Get Version Data.
     *
     * @return array
     */
    public static function getVersionData()
    {
        return [
            'shop_version' => _PS_VERSION_,
            'client'       => SibsConstants::SIBS_DISPLAY_NAME,
            'email'        => Configuration::get('SIBS_GENERAL_CLIENTID'),
            'terminalid'   => Configuration::get('SIBS_GENERAL_TERMINALID'),
            'bearer'       => Configuration::get('SIBS_GENERAL_BEARER'),
            'shop_system'  => SibsConstants::SIBS_SHOP_SYSTEM,
            'ip_address'   => self::getIpAddress(),
        ];
    }

    /**
     * Get Version Data.
     *
     * @return array
     */
    public static function getIpAddress()
    {
        try {
            if (isset($_SERVER['SERVER_ADDR'])) {
                return $_SERVER['SERVER_ADDR'];
            } elseif (isset($_SERVER['LOCAL_ADDR'])) {
                return $_SERVER['LOCAL_ADDR'];
            } else {
                return gethostbyname($_SERVER['SERVER_NAME']);
            }
        } catch (Exception $e) {
            SibsLogger::warning('Could not Get IP Address: ' . $e->getMessage());

            return '127.0.0.1';
        }
    }

    /**
     * Validate Configuration POST.
     *
     * @return void
     */
    private function validateConfigurationPost()
    {
        if (Tools::isSubmit('btnSubmit')) {
            $fieldsRequired = [];
            $isRequired     = false;

            if (empty(trim(Tools::getValue('SIBS_GENERAL_CLIENTID')))) {
                $fieldsRequired[] = $this->l('Merchant Email');
                $isRequired       = true;
            }

            if (empty(trim(Tools::getValue('SIBS_GENERAL_TERMINALID')))) {
                $fieldsRequired[] = $this->l('Terminal ID');
                $isRequired       = true;
            }

            if (empty(trim(Tools::getValue('SIBS_GENERAL_BEARER')))) {
                $fieldsRequired[] = $this->l('Bearer Token');
                $isRequired       = true;
            }

            if ($isRequired) {
                $warning = implode(', ', $fieldsRequired) . ' ';
                $warning .= $this->l('is required. please fill out this field');

                $this->html .= $this->displayWarning($warning);
            } else {
                $this->configurationPost();
            }
        }
    }

    /**
     * Configuration POST.
     *
     * @return void
     */
    private function configurationPost()
    {
        Configuration::updateValue(
            'SIBS_GENERAL_CLIENTID',
            Tools::getValue('SIBS_GENERAL_CLIENTID')
        );

        Configuration::updateValue(
            'SIBS_GENERAL_TERMINALID',
            Tools::getValue('SIBS_GENERAL_TERMINALID')
        );

        Configuration::updateValue(
            'SIBS_GENERAL_BEARER',
            Tools::getValue('SIBS_GENERAL_BEARER')
        );

        Configuration::updateValue(
            'SIBS_WEBHOOK_SECRET',
            Tools::getValue('SIBS_WEBHOOK_SECRET')
        );

        Configuration::updateValue(
            'SIBS_GENERAL_ENVIRONMENT',
            Tools::getValue('SIBS_GENERAL_ENVIRONMENT')
        );

        foreach ($this->payment_methods as $value) {
            Configuration::updateValue(
                "SIBS_{$value}_ACTIVE",
                Tools::getValue("SIBS_{$value}_ACTIVE")
            );

            // debit/authorization methods
            if (in_array($value, $this->payment_authorizations_methods)) {
                Configuration::updateValue(
                    "SIBS_{$value}_MODE",
                    Tools::getValue("SIBS_{$value}_MODE")
                );
            }

            Configuration::updateValue(
                "SIBS_{$value}_SORT",
                Tools::getValue("SIBS_{$value}_SORT")
            );

            // card payment methods
            if (in_array($value, $this->card_payment_methods)) {
                $cards       = Tools::getValue("SIBS_{$value}_CARDS");
                $multiSelect = is_array($cards) ? implode(',', $cards) : '';

                Configuration::updateValue(
                    "SIBS_{$value}_CARDS",
                    $multiSelect
                );
            }

            // credit card method
            if ($value == SibsConstants::PAYMENT_METHOD_CREDIT_CARD) {
                Configuration::updateValue(
                    "SIBS_{$value}_ONECLICK",
                    Tools::getValue("SIBS_{$value}_ONECLICK")
                );
            }

            // pay by link method
            if ($value == SibsConstants::PAYMENT_METHOD_PAY_BY_LINK) {
                Configuration::updateValue(
                    "SIBS_{$value}_EXPIRATION_PAYMENT_TYPE",
                    Tools::getValue("SIBS_{$value}_EXPIRATION_PAYMENT_TYPE")
                );

                Configuration::updateValue(
                    "SIBS_{$value}_EXPIRATION_PAYMENT_VALUE",
                    Tools::getValue("SIBS_{$value}_EXPIRATION_PAYMENT_VALUE")
                );
            }

            // blik method
            if ($value == SibsConstants::PAYMENT_METHOD_BLIK) {
                Configuration::updateValue(
                    "SIBS_{$value}_NUMBER_OF_RETRIES_VALUE",
                    Tools::getValue("SIBS_{$value}_NUMBER_OF_RETRIES_VALUE")
                );

                Configuration::updateValue(
                    "SIBS_{$value}_DELAY_BETWEEN_RETRIES_VALUE",
                    Tools::getValue("SIBS_{$value}_DELAY_BETWEEN_RETRIES_VALUE")
                );
            }

            // Xpay
            if ($value == SibsConstants::PAYMENT_METHOD_XPAY) {
                $domain_onboarding_file_name      = 'apple-developer-merchantid-domain-association';
                $domain_onboarding_file_directory = '.well-known';
                $onboarding_file_dir              = _PS_ROOT_DIR_ . '/' . $domain_onboarding_file_directory;
                $onboarding_file_path             = $onboarding_file_dir . '/' . $domain_onboarding_file_name;

                if (! file_exists($onboarding_file_dir) && ! @mkdir($onboarding_file_dir, 0755)) {
                    SibsLogger::info('Can not on-board Apple Pay merchant: Can not create directory');
                }

                SibsLogger::info('file_name.....');
                SibsLogger::info(SibsLogger::prettify($_FILES));

                /* Checks whether the background image has been successfully uploaded */
                if (isset($_FILES['SIBS_XPAY_MERCHANTID_DOMAIN_ASSOCIATION'])) {
                    if (! move_uploaded_file($_FILES['SIBS_XPAY_MERCHANTID_DOMAIN_ASSOCIATION']['tmp_name'], $onboarding_file_path)) {
                        SibsLogger::info('Can not on-board Apple Pay merchant: Can not locate on-boarding file');
                    }
                }

                Configuration::updateValue(
                    "SIBS_{$value}_MERCHANTID_DOMAIN_ASSOCIATION",
                    Tools::getValue("SIBS_{$value}_MERCHANTID_DOMAIN_ASSOCIATION")
                );
            }
        }

        $chUpdated = $this->l('Saved with Success');

        $this->html .= $this->displayConfirmation($chUpdated);
    }

    /**
     * Get Content.
     *
     * @return string
     */
    public function getContent()
    {
        if (Tools::isSubmit('btnSubmit')) {
            $this->validateConfigurationPost();
        } elseif (Configuration::get('SIBS_POPUP')) {
            Configuration::updateValue('SIBS_POPUP', false);
        } else {
            $this->html .= '<br/>';
        }

        $popUpInfo = $this->context->smarty->fetch("{$this->local_path}views/templates/admin/popUpInfo.tpl");

        $this->html .= $popUpInfo;

        $this->html .= (SibsConstants::SIBS_MULTCURRENCY == true) ?
            $this->configuration() :
            $this->renderForm();

        // $this->html .= $this->renderReportingField();

        return $this->html;
    }

    /**
     * Configuration.
     *
     * @return mixed
     */
    protected function configuration()
    {
        $terminals        = SibsTerminal::getTerminalSibs();
        $environment_file = self::getEnvironmentConfig();

        die($environment_file);

        foreach ($environment_file['environment'] as $value) {
            $environment[$value] = $value;
        }

        $tplVars = [
            'terminals'                   => $terminals,
            'environments'                => $environment,
        ];

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

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

    /**
     * Render Reporting Field.
     *
     * @return mixed
     */
    protected function renderReportingField()
    {
        $reportLocale    = $this->getReportLocale();
        $browser         = new SibsBrowser($_SERVER['HTTP_USER_AGENT']);

        $tplVars = [
            'title'               => $reportLocale['raisingIssue'],
            'reportLabel'         => $reportLocale['report'],
            'sibs_plugin'         => _PS_VERSION_,
            'sibs_plugin_version' => SibsConstants::SIBS_PLUGIN_VESION,
            'sibs_client'         => Configuration::get('SIBS_GENERAL_CLIENTID'),
            'sibs_php_version'    => phpversion(),
            'browser_info'        => $browser->__toString(),
            'browser_get'         => $browser->getBrowser(),
        ];

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

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

    /**
     * Render Form.
     *
     * @return void
     */
    public function renderForm()
    {
        $locale      = $this->getLocaleForm();
        $generalForm = $this->getGeneralForm($locale);
        $paymentForm = $this->getPaymentForm($locale);
        $fieldsForm  = array_merge($generalForm, $paymentForm);

        $helper                        = new HelperForm();
        $helper->show_toolbar          = false;
        $helper->table                 = $this->name . 'criterion';
        $lang                          = new Language((int) Configuration::get('PS_LANG_DEFAULT'));
        $helper->default_form_language = $lang->id;

        $helper->allow_employee_form_lang = (int) Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG');

        $this->fields_form = $fieldsForm;

        $helper->id            = (int) Tools::getValue('id_carrier');
        $helper->identifier    = $this->identifier;
        $helper->submit_action = 'btnSubmit';
        $helper->currentIndex  = $this->context->link->getAdminLink(
            'AdminModules',
            false
        ) . "&configure={$this->name}&tab_module={$this->tab}&module_name={$this->name}";

        $helper->token = Tools::getAdminTokenLite('AdminModules');

        $helper->tpl_vars = [
            'fields_value'          => $this->getConfigFieldsValues(),
            'languages'             => $this->context->controller->getLanguages(),
            'id_language'           => $this->context->language->id,
            'css'                   => $this->context->controller->addCSS(($this->_path) . 'views/css/payment_options.css', 'all'),
            'backOfficeJsUrlSteps'  => $this->context->controller->addJS(($this->_path) . 'views/js/jquery.steps.min.js', 'all'),
            'js'                    => $this->context->controller->addJS(($this->_path) . 'views/js/sibs-setting.js', 'all'),
        ];

        return $helper->generateForm($this->fields_form);
    }

    /**
     * Get Report Locale.
     *
     * @return string
     */
    private function getReportLocale()
    {
        return [
            'raisingIssue' => $this->l('Raise an Issue'),
            'report'       => $this->l('Report feedback'),
        ];
    }

    /**
     * Get Locale Form.
     *
     * @return array
     */
    private function getLocaleForm()
    {
        return [
            'TITLE_GENERAL_SETTING' => $this->l('GENERAL SETTING'),
            'general'               => $this->l('General Setting'),
            'clientid'              => [
                'label' => $this->l('Client ID'),
            ],
            'terminalid' => [
                'label' => $this->l('Terminal ID'),
            ],
            'bearer' => [
                'label' => $this->l('Bearer Token'),
            ],
            'webhook_secret' => [
                'label' => $this->l('Webhook Secret'),
                'desc'  => $this->getWebhookLink() . $this->getPHPSodiumVersion(),
            ],
            'sibs_environment' => [
                'label' => $this->l('Environment'),
            ],
            'recurring' => $this->l('Recurring'),
            'amount'    => [
                'label' => $this->l('Amount for Registration'),
                'desc'  => $this->l('Amount that is debited and refunded when a shopper registers a payment method without purchase.'),
            ],
            'cc'     => $this->l('SIBS Credit Card'),
            'active' => [
                'label' => $this->l('Enabled'),
            ],
            'mode' => [
                'label' => $this->l('Transaction-Mode'),
                'db'    => $this->l('Debit'),
                'pa'    => $this->l('Pre-Authorization'),
            ],
            'cardtype' => [
                'label'  => $this->l('Cards Types'),
                'desc'   => $this->l('Hold Ctrl while selecting the card you want to activate the payment gateway for the selected card.'),
                'visa'   => $this->l('VISA'),
                'master' => $this->l('MASTER'),
            ],
            'oneclick' => [
                'label'        => $this->l('Tokenization'),
                'none'         => $this->l('None'),
                'tokenization' => $this->l('Tokenization'),
                'oneclick'     => $this->l('OneClick'),
            ],
            'order' => [
                'label' => $this->l('Sort Order'),
            ],
            'blik'                     => $this->l('SIBS BLIK'),
            'pay_by_link'              => $this->l('SIBS Pay By Link'),
            'payment_expiration_value' => [
                'label' => $this->l('Expiration Value'),
            ],
            'payment_expiration_type' => [
                'label'  => $this->l('Expiration Type'),
                'minute' => $this->l('Minute'),
                'hour'   => $this->l('Hour'),
                'day'    => $this->l('Day'),
                'month'  => $this->l('Month'),
            ],
            'number_of_retries' => [
                'label' => $this->l('SIBS BLIK Number of Retries'),
            ],
            'delay_between_retries' => [
                'label' => $this->l('SIBS BLIK Retry Delay (seconds)'),
            ],
            'xpay'                               => $this->l('SIBS Apple Pay/ Google Pay'),
            'xpay_merchantid_domain_association' => [
                'label' => $this->l('Merchant Id Domain Association'),
                'desc'  => SibsUtils::replaceKeyToData($this->l('To learn more about how to do this, visit our [site]'), ['site' => 'https://www.docs.pay.sibs.com/payment-methods/google-pay/#make-a-payment']),
            ],
            'save' => $this->l('Save'),
        ];
    }

    /**
     * Get Webhook URL.
     *
     * @return string
     */
    private function getWebhookLink()
    {
        return SibsUtils::replaceKeyToData(
            $this->l('Provide this WebHook URL [link] to your SIBS point of contact.'),
            [
                'link' => $this->getWebhookURL(),
            ]
        );
    }

    /**
     * Get Webhook URL.
     *
     * @return array
     */
    private function getWebhookURL()
    {
        $shopUrl    = Tools::getHttpHost(true) . __PS_BASE_URI__;
        $baseUrl    = str_replace('/shop', '', $shopUrl);
        $webhookUrl = $baseUrl . 'sibs/webhook';

        return $webhookUrl;
    }

    /**
     * Get Payment Form.
     *
     * @param string $locale
     * @return array
     */
    private function getPaymentForm($locale)
    {
        $paymentForm = [];

        foreach ($this->payment_methods as $key => $value) {
            $paymentName   = Tools::strtolower($value);
            $paymentForm[] = [
                'form' => [
                    'legend' => [
                        'title' => $locale["$paymentName"],
                    ],
                    'input' => [
                        $this->getSwitchForm(
                            "{$value}_ACTIVE",
                            $locale['active'],
                            $this->getSwitchList('active')
                        ),
                        $this->getTextForm(
                            "{$value}_SORT",
                            $locale['order']
                        ),
                    ],
                    'submit' => [
                        'title' => $locale['save'],
                    ],
                ],
            ];

            if (in_array($value, $this->payment_authorizations_methods)) {
                if ($value == SibsConstants::PAYMENT_METHOD_CREDIT_CARD) {
                    // card db or pa (drop down menu)
                    $addTransactionMode = $this->getSelectForm(
                        "{$value}_MODE",
                        $locale['mode'],
                        $this->getTransactionModeList(
                            $locale['mode']['db'],
                            $locale['mode']['pa']
                        )
                    );

                    array_push($paymentForm[$key]['form']['input'], $addTransactionMode);

                    // card oneclick date Type (drop down menu)
                    $paymentDate = $this->getSelectForm(
                        "{$value}_ONECLICK",
                        $locale['oneclick'],
                        $this->getOneclickList(
                            $locale['oneclick']['none'],
                            $locale['oneclick']['tokenization'],
                            $locale['oneclick']['oneclick']
                        )
                    );
                    array_push($paymentForm[$key]['form']['input'], $paymentDate);
                }
            }

            if (in_array($value, $this->card_payment_methods)) {
                $cardTypesList = $this->getCCTypesList($locale['cardtype']);

                $addCardType = $this->getMultiSelectForm("{$value}_CARDS", $locale['cardtype'], $cardTypesList);
                array_push($paymentForm[$key]['form']['input'], $addCardType);
            }

            if ($value == SibsConstants::PAYMENT_METHOD_XPAY) {
                // michel
                $paymentRetriesValue = $this->getUploadForm("{$value}_MERCHANTID_DOMAIN_ASSOCIATION", $locale['xpay_merchantid_domain_association']);
                array_push($paymentForm[$key]['form']['input'], $paymentRetriesValue);
            }
        }

        return $paymentForm;
    }

    /**
     * Get General Form.
     *
     * @param array $locale
     * @return array
     */
    private function getGeneralForm($locale)
    {
        //get environment variables from configuration file
        $environment_file = self::getEnvironmentConfig();

        foreach ($environment_file['environment'] as $value) {
            $environment[$value] = $value;
        }

        $generalForm = [];

        $generalForm[] = [
            'form' => [
                'legend' => [
                    'title' => $locale['TITLE_GENERAL_SETTING'],
                ],
                'input' => [
                    $this->getTextForm(
                        'GENERAL_TERMINALID',
                        $locale['terminalid'],
                        true
                    ),
                    $this->getTextAreaForm(
                        'GENERAL_BEARER',
                        $locale['bearer'],
                        true
                    ),
                    $this->getTextForm(
                        'GENERAL_CLIENTID',
                        $locale['clientid'],
                        true
                    ),
                    $this->getSelectForm(
                        'GENERAL_ENVIRONMENT',
                        $locale['sibs_environment'],
                        $this->getSibsEnvironmentConfigLists(
                            $environment
                        )
                    ),
                    $this->getTextForm(
                        'WEBHOOK_SECRET',
                        $locale['webhook_secret']
                    ),
                ],
                'submit' => [
                    'title' => $locale['save'],
                ],
            ],
        ];

        return $generalForm;
    }

    /**
     * Get Textarea Form.
     *
     * @param string $paymentMethod
     * @param string $locale
     * @param bool $requirement
     * @return array
     */
    private function getTextAreaForm($paymentMethod, $locale, $requirement = false)
    {
        $textForm = [
            'type'     => 'textarea',
            'name'     => "SIBS_{$paymentMethod}",
            'label'    => $locale['label'],
            'required' => $requirement,
            'desc'     => isset($locale['desc']) ? $locale['desc'] : '',
        ];

        return $textForm;
    }

    /**
     * Get Text Form.
     *
     * @param string $paymentMethod
     * @param string $locale
     * @param bool $requirement
     * @return array
     */
    private function getTextForm($paymentMethod, $locale, $requirement = false)
    {
        $textForm = [
            'type'     => 'text',
            'name'     => "SIBS_{$paymentMethod}",
            'label'    => $locale['label'],
            'required' => $requirement,
            'desc'     => isset($locale['desc']) ? $locale['desc'] : '',
        ];

        return $textForm;
    }

    /**
     * Get Upload Form.
     *
     * @param string $paymentMethod
     * @param string $locale
     * @param bool $requirement
     * @return array
     */
    private function getUploadForm($paymentMethod, $locale, $requirement = false)
    {
        $textForm = [
            'type'     => 'file',
            'name'     => "SIBS_{$paymentMethod}",
            'label'    => $locale['label'],
            'required' => $requirement,
            'desc'     => isset($locale['desc']) ? $locale['desc'] : '',
        ];

        return $textForm;
    }

    /**
     * Get Select Form.
     *
     * @param string $paymentMethod
     * @param string $locale
     * @param array $selectList
     * @return array
     */
    private function getSelectForm($paymentMethod, $locale, $selectList)
    {
        $selectForm = [
            'type'    => 'select',
            'name'    => "SIBS_{$paymentMethod}",
            'label'   => $locale['label'],
            'options' => [
                'query' => $selectList,
                'id'    => 'id',
                'name'  => 'name',
            ],
            'desc' => ! empty($locale['desc']) ? $locale['desc'] : '',
        ];

        return $selectForm;
    }

    /**
     * Get MultiSelect Form.
     *
     * @param string $paymentMethod
     * @param string $locale
     * @param array $multiSelectList
     * @return array
     */
    private function getMultiSelectForm($paymentMethod, $locale, $multiSelectList)
    {
        $selectForm = [
            'id'       => "SIBS_{$paymentMethod}",
            'type'     => 'select',
            'name'     => "SIBS_{$paymentMethod}[]",
            'label'    => $locale['label'],
            'multiple' => true,
            'options'  => [
                'query' => $multiSelectList,
                'id'    => 'id',
                'name'  => 'name',
            ],
            'desc' => ! empty($locale['desc']) ? $locale['desc'] : '',
        ];

        return $selectForm;
    }

    /**
     * Get Switch Form.
     *
     * @param string $paymentMethod
     * @param string $locale
     * @param array $switchList
     * @return array
     */
    private function getSwitchForm($paymentMethod, $locale, $switchList)
    {
        $switchForm = [
            'type'    => 'switch',
            'label'   => $locale['label'],
            'name'    => "SIBS_{$paymentMethod}",
            'is_bool' => true,
            'values'  => $switchList,
            'desc'    => ! empty($locale['desc']) ? $locale['desc'] : '',
        ];

        return $switchForm;
    }

    /**
     * Get Switch List.
     *
     * @param string $field
     * @return array
     */
    private function getSwitchList($field)
    {
        $list = [
            [
                'id'    => "{$field}_on",
                'value' => 1,
            ], [
                'id'    => "{$field}_off",
                'value' => 0,
            ],
        ];

        return $list;
    }

    /**
     * Get Pay By Link List.
     *
     * @param string $chModeMinute
     * @param string $chModeHour
     * @param string $chModeDay
     * @param string $chModeMonth
     * @return array
     */
    private function getPblList($chModeMinute, $chModeHour, $chModeDay, $chModeMonth)
    {
        $listChServer = [
            [
                'id'   => 'minute',
                'name' => $chModeMinute,
            ], [
                'id'   => 'hour',
                'name' => $chModeHour,
            ], [
                'id'   => 'day',
                'name' => $chModeDay,
            ], [
                'id'   => 'month',
                'name' => $chModeMonth,
            ],
        ];

        return $listChServer;
    }

    /**
     * Get Oneclick List.
     *
     * @param string $chModeNone
     * @param string $chModeTokenization
     * @param string $chModeOneclick
     * @return array
     */
    private function getOneclickList($chModeNone, $chModeTokenization, $chModeOneclick)
    {
        $listChServer = [
            [
                'id'   => SibsConstants::SIBS_TOKEN_NONE,
                'name' => $chModeNone,
            ], [
                'id'   => SibsConstants::SIBS_TOKEN_TOKENIZATION,
                'name' => $chModeTokenization,
            ], [
                'id'   => SibsConstants::SIBS_TOKEN_ONECLICK,
                'name' => $chModeOneclick,
            ],
        ];

        return $listChServer;
    }

    /**
     * Get SIBS Environment Config Lists.
     *
     * @param array $options
     * @return array
     */
    private function getSibsEnvironmentConfigLists($options)
    {
        $listSibsConfigs = [];

        if (is_array($options)) {
            foreach ($options as $list) {
                $listSibsConfigs[] = [
                    'id'   => $list,
                    'name' => $list,
                ];
            }
        }

        return $listSibsConfigs;
    }

    /**
     * Get Transaction Mode List.
     *
     * @param string $chModeDebit
     * @param string $chModePreauth
     * @return array
     */
    private function getTransactionModeList($chModeDebit, $chModePreauth)
    {
        $listChMode = [
            [
                'id'   => SibsConstants::PAYMENT_MODE_DEBIT,
                'name' => $chModeDebit,
            ], [
                'id'   => SibsConstants::PAYMENT_MODE_AUTH,
                'name' => $chModePreauth,
            ],
        ];

        return $listChMode;
    }

    /**
     * Get Credit Card Types List.
     *
     * @param array $cardTypes
     * @return array
     */
    private function getCCTypesList($cardTypes)
    {
        $listChCardType = [
            [
                'id'   => SibsConstants::SIBS_CREDIT_CARD_MASTER,
                'name' => $cardTypes['master'],
            ],
            [
                'id'   => SibsConstants::SIBS_CREDIT_CARD_VISA,
                'name' => $cardTypes['visa'],
            ],
        ];

        return $listChCardType;
    }

    /**
     * SIBS Order Status.
     *
     * @param array $sibsOrder
     * @return void
     */
    public function sibsOrderStatus($sibsOrder)
    {
        SibsLogger::info('INIT ORDER_STATUS');

        try {
            $orderID       = $sibsOrder['id_order'];
            $transactionID = $sibsOrder['id_transaction'];

            SibsLogger::info("orderId: $orderID");
            SibsLogger::info("transactionID: $transactionID");

            $credentials = SibsUtils::getCredentials();
            $resultJson  = SibsPaymentCore::getPaymentStatus($transactionID, $credentials);

            SibsLogger::info("resultJson: $resultJson");

            if (! $resultJson) {
                throw new SibsException('ERROR_GENERAL_NORESPONSE');
            }

            $response              = $resultJson['response'];
            $paymentStatus         = $response['paymentStatus'];
            $returnCode            = $response['returnStatus']['statusCode'];
            $captureAmountCurrency = $response['amount']['currency'];
            $captureAmount         = $response['amount']['value'];

            SibsLogger::info('Status: ' . SibsLogger::prettify($response));
            SibsLogger::info("returnCode: $returnCode");
            SibsLogger::info("paymentStatus: $paymentStatus");

            $transactionResult = SibsPaymentCore::getTransactionResult($returnCode, $paymentStatus);

            if ($transactionResult !== SibsConstants::SIBS_ACK) {
                throw new SibsException('Error on Order Status');
            }

            if ($response['paymentStatus'] == SibsConstants::PAYMENT_STATUS_SUCCESS) {
                $employeeID = (int) $this->context->employee->id;
                SibsPaymentCore::saveOrderHistory($orderID, SibsConstants::ORDER_STATUS_PAYMENT, $employeeID);
            }

            $resultJsonLog = [
                'transactionID' => $transactionID,
                'paymentType'   => $response['paymentType'],
                'paymentStatus' => $response['paymentStatus'],
                'amount'        => [
                    'currency' => $captureAmountCurrency,
                    'value'    => $captureAmount,
                ],
            ];

            try {
                SibsOrderRefLog::saveTransactionRefundLog($orderID, '(Order Status) ' . $response['paymentStatus'], $resultJsonLog);
            } catch (Exception $e) {
                SibsLogger::info($e->getMessage());
            }

            $this->adminStatusConfirmationMessage(
                $this->l('Status check complete'),
                SibsUtils::replaceKeyToData($this->l('Status complete (ACK) for order #[orderId]'), ['orderId' => $orderID])
            );
        } catch(SibsException $e) {
            $error   = SibsPaymentCore::getErrorIdentifier();
            $message = $e->getErrorMessage();

            $this->adminStatusErrorMessage($error, $message, []);
        }

        $this->context->smarty->assign('refresh_page', true);
        SibsLogger::info('END ORDER_STATUS');
    }

    /**
     * SIBS Capture.
     *
     * @param array $sibsOrder
     * @return void
     */
    public function sibsCapture($sibsOrder)
    {
        SibsLogger::info('INIT CAPTURE');

        try {
            $orderID       = (int) $sibsOrder['id_order'];
            $transactionID = $sibsOrder['id_transaction'];
            $captureAmount = Tools::getValue('capture_amount');

            $transactionData = $this->getTransactionalCaptureData($sibsOrder, $captureAmount);
            $resultJson      = SibsPaymentCore::backOfficeOperation($transactionID, $transactionData);

            if (! $resultJson) {
                throw new SibsException('ERROR_GENERAL_NORESPONSE');
            }

            $response = $resultJson['response'];

            $returnCode            = $response['returnStatus']['statusCode'];
            $captureStatus         = $response['paymentStatus'];
            $captureID             = $response['transactionID'];
            $captureAmountCurrency = $response['amount']['currency'];
            $data                  = [
                'orderID'  => $orderID,
                'amount'   => $captureAmount,
                'currency' => $captureAmountCurrency,
            ];

            SibsOrderRef::updateOrderRefCaptureStatus(
                $orderID,
                SibsPaymentCore::sibs_convert_response_status_to_capture_payment_status($captureStatus)
            );

            $transactionResult = SibsPaymentCore::getTransactionResult($returnCode, $captureStatus);

            if ($transactionResult !== SibsConstants::SIBS_ACK) {
                throw new SibsException('Error on Capture');
            }

            SibsOrderRef::updateOrderRefCaptureID($orderID, $captureID);

            $sibsOrder = new Order($orderID);

            $resultJsonLog = [
                'transactionID' => $response['transactionID'],
                'paymentType'   => $transactionData['paymentType'],
                'paymentStatus' => $response['paymentStatus'],
                'amount'        => [
                    'currency' => $captureAmountCurrency,
                    'value'    => $captureAmount,
                ],
            ];

            try {
                SibsOrderRefLog::saveTransactionRefundLog($orderID, SibsConstants::PAYMENT_TYPE_CAPT, $resultJsonLog);
            } catch (Exception $e) {
                SibsLogger::info($e->getMessage());
            }

            $employeeID = (int) $this->context->employee->id;
            SibsPaymentCore::saveOrderHistory($orderID, SibsConstants::ORDER_STATUS_PAYMENT, $employeeID);

            $message = SibsUtils::replaceKeyToData($this->l('Capture done for order #[orderId] with [amount] [currency]'), $data);
            SibsOrderRef::updateOrderRefCaptureMessage($orderID, $message);

            $this->adminStatusConfirmationMessage('Capture complete', $message, $data);
        } catch(SibsException $e) {
            $error   = SibsPaymentCore::getErrorIdentifier();
            $message = $e->getErrorMessage();

            $this->adminStatusErrorMessage($error, $message, []);
        }

        $this->context->smarty->assign('refresh_page', true);
        SibsLogger::info('END CAPTURE');
    }

    /**
     * SIBS Refund.
     *
     * @param string $sibsOrder
     * @param string $PsOrder
     * @param array $params
     * @return void
     */
    public function sibsRefundParcial($sibsOrder, $PsOrder, $params)
    {
        // @todo: criação de uma versao para fazer devolucao parcial.
        SibsLogger::info('INIT SIBS_REFUND_PARCIAL');

        try {
            $orderID       = (int) ($sibsOrder['id_order']);
            $paymentType   = $sibsOrder['payment_type'];
            $transactionID = ($paymentType === SibsConstants::PAYMENT_TYPE_AUTH) ? $sibsOrder['id_captured'] : $sibsOrder['id_transaction'];
            $refundAmount  = round($params['cancel_amount'], 2);

            $transactionData = $this->getTransactionalRefundData($sibsOrder, $refundAmount);
            $resultJson      = SibsPaymentCore::backOfficeOperation($transactionID, $transactionData);

            if (! $resultJson) {
                throw new SibsException('ERROR_GENERAL_NORESPONSE');
            }

            $response = $resultJson['response'];

            if (! isset($response['paymentStatus'])) {
                throw new SibsException('ERROR_GENERAL_NORESPONSE');
            }

            $returnCode           = $response['returnStatus']['statusCode'];
            $refundStatus         = $response['paymentStatus'];
            $refundID             = $response['transactionID'];
            $refundAmountCurrency = $response['amount']['currency'];

            $data = [
                'orderId'  => $orderID,
                'amount'   => $refundAmount,
                'currency' => $refundAmountCurrency,
            ];

            SibsOrderRef::updateOrderRefRefundStatus($orderID, $refundStatus);

            $transactionResult = SibsPaymentCore::getTransactionResult(
                $returnCode,
                SibsPaymentCore::sibs_convert_response_status_to_capture_payment_status($refundStatus)
            );

            if ($transactionResult !== SibsConstants::SIBS_ACK) {
                throw new SibsException('Error on Refund');
            }

            $resultJsonLog = [
                'transactionID' => $response['transactionID'],
                'paymentType'   => $transactionData['paymentType'],
                'paymentStatus' => $response['paymentStatus'],
                'amount'        => [
                    'currency' => $refundAmountCurrency,
                    'value'    => $refundAmount,
                ],
            ];

            SibsOrderRef::updateOrderRefRefundID($orderID, $refundID);
            SibsOrderRefLog::saveTransactionRefundLog($orderID, SibsConstants::PAYMENT_TYPE_RFND, $resultJsonLog);

            $orderRefundStatus = SibsPaymentCore::getOrderRefundStatus($refundStatus);

            $employeeID = (int) $this->context->employee->id;
            SibsPaymentCore::saveOrderHistory($orderID, $orderRefundStatus, $employeeID);

            if ($orderRefundStatus === SibsConstants::ORDER_STATUS_SIBS_REFUND_PENDING) {
                $message         = SibsUtils::replaceKeyToData($this->l('Refund done for order #[orderId] with [amount] [currency]'), $data);
                $completeMessage = 'Refund complete';
            } elseif ($orderRefundStatus === SibsConstants::ORDER_STATUS_REFUND) {
                $message         = SibsUtils::replaceKeyToData($this->l('Refund pending for order #[orderId] with [amount] [currency]'), $data);
                $completeMessage = 'Refund is pending';
            }

            SibsOrderRef::updateOrderRefRefundMessage($orderID, $message);

            $this->adminStatusConfirmationMessage($completeMessage, $message, $data);
        } catch(SibsException $e) {
            SibsLogger::info('SibsException SIBS_REFUND_PARCIAL');
            SibsLogger::info($e->getErrorMessage());
            $error   = SibsPaymentCore::getErrorIdentifier();
            $message = $e->getErrorMessage();

            $this->adminStatusErrorMessage($error, $message, []);
        }

        $this->context->smarty->assign('refresh_page', true);
        SibsLogger::info('END SIBS_REFUND_PARCIAL');
    }

    /**
     * SIBS Refund.
     *
     * @param array $sibsOrder
     * @return void
     */
    public function sibsRefund($sibsOrder)
    {
        SibsLogger::info('INIT SIBS_REFUND');

        try {
            $orderID       = (int) ($sibsOrder['id_order']);
            $paymentType   = $sibsOrder['payment_type'];
            $transactionID = ($paymentType === SibsConstants::PAYMENT_TYPE_AUTH) ? $sibsOrder['id_captured'] : $sibsOrder['id_transaction'];
            $refundAmount  = Tools::getValue('refund_amount');

            $transactionData = $this->getTransactionalRefundData($sibsOrder, $refundAmount);

            $resultJson = SibsPaymentCore::backOfficeOperation($transactionID, $transactionData);

            if (! $resultJson) {
                throw new SibsException('ERROR_GENERAL_NORESPONSE');
            }

            $response             = $resultJson['response'];
            $returnCode           = $response['returnStatus']['statusCode'];
            $refundStatus         = $response['paymentStatus'];
            $refundID             = $response['transactionID'];
            $refundAmountCurrency = $response['amount']['currency'];

            $data = [
                'orderId'  => $orderID,
                'amount'   => $refundAmount,
                'currency' => $refundAmountCurrency,
            ];

            SibsOrderRef::updateOrderRefRefundStatus($orderID, $refundStatus);
            $transactionResult = SibsPaymentCore::getTransactionResult(
                $returnCode,
                SibsPaymentCore::sibs_convert_response_status_to_capture_payment_status($refundStatus)
            );

            if ($transactionResult !== SibsConstants::SIBS_ACK) {
                throw new SibsException('Error on Refund');
            }

            $resultJsonLog = [
                'transactionID' => $response['transactionID'],
                'paymentType'   => $transactionData['paymentType'],
                'paymentStatus' => $response['paymentStatus'],
                'amount'        => [
                    'currency' => $refundAmountCurrency,
                    'value'    => $refundAmount,
                ],
            ];

            SibsOrderRef::updateOrderRefRefundID($orderID, $refundID);
            SibsOrderRefLog::saveTransactionRefundLog($orderID, SibsConstants::PAYMENT_TYPE_RFND, $resultJsonLog);

            $orderRefundStatus = SibsPaymentCore::getOrderRefundStatus($refundStatus);

            $employeeID = (int) $this->context->employee->id;
            SibsPaymentCore::saveOrderHistory($orderID, $orderRefundStatus, $employeeID);

            if ($orderRefundStatus === SibsConstants::ORDER_STATUS_SIBS_REFUND_PENDING) {
                $message         = SibsUtils::replaceKeyToData($this->l('Refund done for order #[orderId] with [amount] [currency]'), $data);
                $completeMessage = 'Refund complete';
            } elseif ($orderRefundStatus === SibsConstants::ORDER_STATUS_REFUND) {
                $message         = SibsUtils::replaceKeyToData($this->l('Refund pending for order #[orderId] with [amount] [currency]'), $data);
                $completeMessage = 'Refund is pending';
            }

            SibsOrderRef::updateOrderRefRefundMessage($orderID, $message);

            $this->adminStatusConfirmationMessage($completeMessage, $message, $data);
        } catch(SibsException $e) {
            $error   = SibsPaymentCore::getErrorIdentifier();
            $message = $e->getErrorMessage();

            $this->adminStatusErrorMessage($error, $message, []);
        }

        $this->context->smarty->assign('refresh_page', true);
        SibsLogger::info('END SIBS_REFUND');
    }

    /**
     * SIBS Make Context.
     *
     * @param array $sibsOrder
     * @return void
     */
    public function sibsMakeContext($sibsOrder)
    {
        SibsLogger::info('INIT SIBS_MAKE_CONTEXT');

        $key_show_order_status = null;
        $key_show_sibs_capture = null;
        $key_show_sibs_refund  = null;
        $key_show_refund       = null;

        $orderID  = (int) ($sibsOrder['id_order']);
        $order    = new Order($orderID);
        $currency = new Currency((int) $order->id_currency);

        $current_state = $order->getCurrentState();

        $payment_method = $sibsOrder['payment_method'];
        $refund_status  = $sibsOrder['refund_status'];

        SibsLogger::info("payment_method: $payment_method");
        SibsLogger::info("refund_status: $refund_status");

        switch ($current_state) {
            case Configuration::get(SibsConstants::ORDER_STATUS_SIBS_PENDING):
                $key_show_order_status = '1';

                break;
            case Configuration::get(SibsConstants::ORDER_STATUS_SIBS_AUTHORIZED):
                $key_show_sibs_capture = '1';

                break;
            case Configuration::get(SibsConstants::ORDER_STATUS_PAYMENT):
                $key_show_refund = '1';

                break;
        }

        if ($refund_status == SibsConstants::CAPTURE_REFUND_STATUS_PENDING) {
            $key_show_sibs_refund = '1';
        }

        SibsLogger::info("key_show_refund: $key_show_refund");
        SibsLogger::info("key_show_sibs_capture: $key_show_sibs_capture");
        SibsLogger::info("key_show_order_status: $key_show_order_status");
        SibsLogger::info("key_show_sibs_refund: $key_show_sibs_refund");

        $this->context->smarty->assign('id_transaction', $sibsOrder['id_transaction']);
        $this->context->smarty->assign('payment_method', $sibsOrder['payment_method']);
        $this->context->smarty->assign('amount', $sibsOrder['amount']);
        $this->context->smarty->assign('currency', $sibsOrder['currency']);

        $this->context->smarty->assign('currency_sign', $currency->sign);

        $this->context->smarty->assign('key_status', $key_show_order_status);
        $this->context->smarty->assign('key_sibs_capture', $key_show_sibs_capture);
        $this->context->smarty->assign('key_sibs_refund', $key_show_sibs_refund);
        $this->context->smarty->assign('key_refund', $key_show_refund);

        SibsLogger::info('END SIBS_MAKE_CONTEXT');
    }

    /**
     * Get Refund Data.
     *
     * @param array $sibsOrder
     * @param string $amount
     * @return array
     */
    private function getTransactionalRefundData($sibsOrder, $amount)
    {
        return $this->getTransactionalData($sibsOrder, $amount, SibsConstants::PAYMENT_MODE_RFND);
    }

    /**
     * Get Capture Data.
     *
     * @param array $sibsOrder
     * @param string $amount
     * @return array
     */
    private function getTransactionalCaptureData($sibsOrder, $amount)
    {
        return $this->getTransactionalData($sibsOrder, $amount, SibsConstants::PAYMENT_MODE_CAPT);
    }

    /**
     * Get Transaction Data.
     *
     * @param array $sibsOrder
     * @param string $amount
     * @param string $paymentType
     * @return array
     */
    private function getTransactionalData($sibsOrder, $amount, $paymentType)
    {
        $credentials   = SibsUtils::getCredentials();
        $config_values = Sibs::getVersionData();

        $transactionData = [
            'test_mode'   => SibsUtils::getTestMode($sibsOrder['payment_method']),
            'paymentType' => $paymentType,
            'amount'      => $amount,
            'currency'    => $sibsOrder['currency'],
            'token'       => $credentials['token'],
            'server_mode' => $credentials['server_mode'],
            'merchant'    => [
                'terminalId'            => $config_values['terminalid'],
                'channel'               => $credentials['channel_id'],
                'merchantTransactionId' => $sibsOrder['id_transaction'],
            ],
            'transaction' => [
                'transactionTimestamp' => date('Y-m-d\TH:i:s.BP'),
                'description'          => "Transaction for order number {$sibsOrder['id_order']} terminalId {$config_values['terminalid']}",
                'amount'               => [
                    'value'    => $amount,
                    'currency' => $sibsOrder['currency'],
                ],
            ],
            'originalTransaction' => [
                'id'       => $sibsOrder['id_transaction'],
                'datetime' => $sibsOrder['payment_date'],
            ],
        ];

        return $transactionData;
    }

    /**
     * Admin Status Confirmation Message.
     *
     * @param string $confirmation
     * @param string $message
     * @return void
     */
    private function adminStatusConfirmationMessage($confirmation, $message)
    {
        $this->context->controller->confirmations[] = $confirmation;
        $this->context->smarty->assign('status_message', $message);
    }

    /**
     * Admin Status Error Message.
     *
     * @param string $error
     * @param string $message
     * @return void
     */
    private function adminStatusErrorMessage($error, $message)
    {
        $this->context->controller->errors[] = $error;
        $this->context->smarty->assign('status_message', $message);
    }

    /**
     * Get Config General Values.
     *
     * @return array
     */
    private function getConfigGeneralValues()
    {
        return [
            'SIBS_GENERAL_CLIENTID' => Tools::getValue(
                'SIBS_GENERAL_CLIENTID',
                Configuration::get('SIBS_GENERAL_CLIENTID')
            ),
            'SIBS_GENERAL_TERMINALID' => Tools::getValue(
                'SIBS_GENERAL_TERMINALID',
                Configuration::get('SIBS_GENERAL_TERMINALID')
            ),
            'SIBS_GENERAL_BEARER' => Tools::getValue(
                'SIBS_GENERAL_BEARER',
                Configuration::get('SIBS_GENERAL_BEARER')
            ),
            'SIBS_WEBHOOK_SECRET' => Tools::getValue(
                'SIBS_WEBHOOK_SECRET',
                Configuration::get('SIBS_WEBHOOK_SECRET')
            ),
            'SIBS_GENERAL_ENVIRONMENT' => Tools::getValue(
                'SIBS_GENERAL_ENVIRONMENT',
                Configuration::get('SIBS_GENERAL_ENVIRONMENT')
            ),
        ];
    }

    /**
     * Get Config Fields Values.
     *
     * @return array
     */
    public function getConfigFieldsValues()
    {
        $saveConfig = $this->getConfigGeneralValues();

        foreach ($this->payment_methods as $value) {
            $saveConfig["SIBS_{$value}_ACTIVE"] = Tools::getValue(
                "SIBS_{$value}_ACTIVE",
                Configuration::get("SIBS_{$value}_ACTIVE")
            );

            // debit/authorization methods
            if (in_array($value, $this->payment_authorizations_methods)) {
                $saveConfig["SIBS_{$value}_MODE"] = Tools::getValue(
                    "SIBS_{$value}_MODE",
                    Configuration::get("SIBS_{$value}_MODE")
                );
            }

            $saveConfig["SIBS_{$value}_SORT"] = Tools::getValue(
                "SIBS_{$value}_SORT",
                Configuration::get("SIBS_{$value}_SORT")
            );

            // card payment methods
            if (in_array($value, $this->card_payment_methods)) {
                $saveConfig["SIBS_{$value}_CARDS[]"] = Tools::getValue(
                    "SIBS_{$value}_CARDS",
                    Configuration::get("SIBS_{$value}_CARDS")
                );

                $saveConfig["SIBS_{$value}_ONECLICK"] = Tools::getValue(
                    "SIBS_{$value}_ONECLICK",
                    Configuration::get("SIBS_{$value}_ONECLICK")
                );
            }

            if ($value == SibsConstants::PAYMENT_METHOD_XPAY) {
                // payment value
                $saveConfig["SIBS_{$value}_MERCHANTID_DOMAIN_ASSOCIATION"] = Tools::getValue(
                    "SIBS_{$value}_MERCHANTID_DOMAIN_ASSOCIATION",
                    Configuration::get("SIBS_{$value}_MERCHANTID_DOMAIN_ASSOCIATION")
                );
            }

            // pay by link method
            if ($value == SibsConstants::PAYMENT_METHOD_PAY_BY_LINK) {
                // payment value
                $saveConfig["SIBS_{$value}_EXPIRATION_PAYMENT_VALUE"] = Tools::getValue(
                    "SIBS_{$value}_EXPIRATION_PAYMENT_VALUE",
                    Configuration::get("SIBS_{$value}_EXPIRATION_PAYMENT_VALUE")
                );

                // payment type
                $saveConfig["SIBS_{$value}_EXPIRATION_PAYMENT_TYPE"] = Tools::getValue(
                    "SIBS_{$value}_EXPIRATION_PAYMENT_TYPE",
                    Configuration::get("SIBS_{$value}_EXPIRATION_PAYMENT_TYPE")
                );

                // payment link value
                $saveConfig["SIBS_{$value}_EXPIRATION_PAYMENT_LINK_VALUE"] = Tools::getValue(
                    "SIBS_{$value}_EXPIRATION_PAYMENT_LINK_VALUE",
                    Configuration::get("SIBS_{$value}_EXPIRATION_PAYMENT_LINK_VALUE")
                );

                // payment link type
                $saveConfig["SIBS_{$value}_EXPIRATION_PAYMENT_LINK_TYPE"] = Tools::getValue(
                    "SIBS_{$value}_EXPIRATION_PAYMENT_LINK_TYPE",
                    Configuration::get("SIBS_{$value}_EXPIRATION_PAYMENT_LINK_TYPE")
                );
            }

            // blik method
            if ($value == SibsConstants::PAYMENT_METHOD_BLIK) {
                $saveConfig["SIBS_{$value}_NUMBER_OF_RETRIES_VALUE"] = Tools::getValue(
                    "SIBS_{$value}_NUMBER_OF_RETRIES_VALUE",
                    Configuration::get("SIBS_{$value}_NUMBER_OF_RETRIES_VALUE")
                );

                $saveConfig["SIBS_{$value}_DELAY_BETWEEN_RETRIES_VALUE"] = Tools::getValue(
                    "SIBS_{$value}_DELAY_BETWEEN_RETRIES_VALUE",
                    Configuration::get("SIBS_{$value}_DELAY_BETWEEN_RETRIES_VALUE")
                );
            }

            if (! Tools::isSubmit('btnSubmit')) {
                $saveConfig["SIBS_{$value}_CARDS[]"] = isset($saveConfig["SIBS_{$value}_CARDS[]"]) ?
                    explode(',', $saveConfig["SIBS_{$value}_CARDS[]"]) :
                    [];
            }
        }

        return $saveConfig;
    }

    /**
     * Get Payment Description.
     *
     * @param string $paymentMethod
     * @return string
     */
    public function getPaymentDescription($paymentMethod)
    {
        $transactionMode = Configuration::get("SIBS_{$paymentMethod}_MODE");

        switch ($paymentMethod) {
            case SibsConstants::PAYMENT_METHOD_CREDIT_CARD:
            case SibsConstants::PAYMENT_METHOD_CARD:
                if ($transactionMode == SibsConstants::PAYMENT_MODE_DEBIT) {
                    return $this->l('Credit Card - Debit');
                } elseif ($transactionMode == SibsConstants::PAYMENT_MODE_AUTH) {
                    return $this->l('Credit Card');
                }

                return '';
            case SibsConstants::PAYMENT_METHOD_BLIK:
                return $this->l('BLIK');
            case SibsConstants::PAYMENT_METHOD_PAY_BY_LINK:
                return $this->l('Pay By Link');
            case SibsConstants::PAYMENT_METHOD_XPAY:
                return $this->l('Apple Pay/ Google Pay');
            default:
                return '';
        }
    }

    /**
     * Get Environment Config.
     *
     * @return array
     */
    public static function getEnvironmentConfig()
    {
        try {
            $json_file        = file_get_contents(_PS_MODULE_DIR_ . 'sibs/environment.json');
            $environment_file = json_decode($json_file, true);

            return $environment_file;
        } catch (Exception $e) {
            SibsLogger::error('Error on accessing environment json: ' . $e->getMessage());

            return [];
        }
    }

    /**
     * Get PHP Sodium Version.
     *
     * @return string
     */
    private function getPHPSodiumVersion()
    {
        $testDecryptor = $this->getTestDecryptor();

        $PHPSodiumVersion = '';

        $PHPSodiumVersion .= '[p][strong]' . $this->l('Sodium Extension') . '[/strong]: ' . (
            ($testDecryptor->canSodiumUseAeadAes256Gcm()) ?
            "[green]{$this->l('Available')}[/green][/p]" :
            "[red]{$this->l('Not Available')}[/red][/p]"
        );

        $PHPSodiumVersion .= '[p][strong]' . $this->l('LibSodium Extension') . '[/strong]: ' . (
            ($testDecryptor->canLibSodiumUseAeadAes256Gcm()) ?
            "[green]{$this->l('Available')}[/green][/p]" :
            "[red]{$this->l('Not Available')}[/red][/p]"
        );

        $PHPSodiumVersion .= '[p][strong]' . $this->l('Sodium Compact') . '[/strong]: ' . (
            ($testDecryptor->canSodiumCompactUseAeadAes256Gcm()) ?
            "[green]{$this->l('Available')}[/green][/p]" :
            "[red]{$this->l('Not Available')}[/red][/p]"
        );

        $PHPSodiumVersion .= '[p][strong]' . $this->l('OpenSSL Extension') . '[/strong]: ' . (
            ($testDecryptor->canOpenSSLUseAeadAes256Gcm()) ?
            "[green]{$this->l('Available')}[/green][/p]" :
            "[red]{$this->l('Not Available')}[/red][/p]"
        );

        $PHPSodiumVersion .= '[p][strong]' . $this->l('Webhook Decryption') . '[/strong]: ' . (
            ($testDecryptor->canUseAes256Gcm()) ?
            "[green]{$this->l('Available')}[/green][/p]" :
            "[red]{$this->l('Not Available')}[/red][/p]"
        );

        $PHPSodiumVersion .= '[p][strong]' . $this->l('Webhook Decryption Test') . '[/strong]: ';

        try {
            $sibsWebhookData = $testDecryptor->execute();
            $PHPSodiumVersion .= '[green]' . SibsLogger::prettify($sibsWebhookData->jsonSerialize()) . '[/green][/p]';
        } catch (Exception $e) {
            $PHPSodiumVersion .= '[red]' . $e->getMessage() . '[/red][/p]';
        }

        return str_replace(
            ['[br]', '[green]', '[/green]', '[red]', '[/red]', '[p]', '[/p]', '[strong]', '[/strong]'],
            ['<br>', '<font color="green">', '</font>', '<font color="red">', '</font>', '<p>', '</p>', '<strong>', '</strong>'],
            $PHPSodiumVersion
        );
    }

    /**
     * Get Test Decryptor.
     *
     * @return SibsWebhookDecryptor
     */
    private function getTestDecryptor(): SibsWebhookDecryptor
    {
        $iv      = '000000000000000000000000';
        $authTag = 'CE573FB7A41AB78E743180DC83FF09BD';
        $content = '0A3471C72D9BE49A8520F79C66BBD9A12FF9';
        $secret  = '000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f';

        return (new SibsWebhookDecryptor($content, $iv, $authTag, $secret))
            ->setSuppressLog(true);
    }
}
