<?php


namespace Tamara\Wp\Plugin;

use Exception;
use Tamara\Wp\Plugin\Dependencies\Illuminate\Container\Container;
use Tamara\Wp\Plugin\Dependencies\Tamara\Model\Money;
use Tamara\Wp\Plugin\Dependencies\Tamara\Model\Payment\Refund;
use Tamara\Wp\Plugin\Dependencies\Tamara\Request\Order\GetOrderByReferenceIdRequest;
use Tamara\Wp\Plugin\Dependencies\Tamara\Request\Payment\RefundRequest;
use Tamara\Wp\Plugin\Helpers\MoneyHelper;
use Tamara\Wp\Plugin\Interfaces\WPPluginInterface;
use Tamara\Wp\Plugin\Services\TamaraNotificationService;
use Tamara\Wp\Plugin\Services\ViewService;
use Tamara\Wp\Plugin\Services\WCTamaraGateway;
use Tamara\Wp\Plugin\Services\WCTamaraGatewayPayNextMonth;
use Tamara\Wp\Plugin\Services\WCTamaraGatewayPayNow;
use Tamara\Wp\Plugin\Services\WCTamaraGatewayCheckout;
use Tamara\Wp\Plugin\Services\WCTamaraGatewayPayByInstalments;
use Tamara\Wp\Plugin\Traits\ConfigTrait;
use Tamara\Wp\Plugin\Traits\ServiceTrait;
use Tamara\Wp\Plugin\Traits\TamaraPaymentTypesTrait;
use Tamara\Wp\Plugin\Traits\WPAttributeTrait;
use WC_Order;
use WP;

class TamaraCheckout extends Container implements WPPluginInterface
{
    use ConfigTrait;
    use WPAttributeTrait;
    use TamaraPaymentTypesTrait;

    /**
     * @var string Tamara CheckoutFrame JS Url
     */
    public const
        TAMARA_SUMMARY_WIDGET_URL = 'https://cdn.tamara.co/widget-v2/tamara-widget.js',
        TAMARA_SUMMARY_WIDGET_SANDBOX_URL = 'https://cdn-sandbox.tamara.co/widget-v2/tamara-widget.js',

        TAMARA_LOGO_BADGE_EN_URL = 'https://cdn.tamara.co/assets/png/tamara-logo-badge-en.png',
        TAMARA_LOGO_BADGE_AR_URL = 'https://cdn.tamara.co/assets/png/tamara-logo-badge-ar.png',
        MESSAGE_LOG_FILE_NAME = 'tamara-custom.log',
        TAMARA_GATEWAY_ID = 'tamara-gateway',
        TAMARA_GATEWAY_PAY_NOW = 'tamara-gateway-pay-now',
        TAMARA_GATEWAY_PAY_NEXT_MONTH = 'tamara-gateway-pay-next-month',
        TAMARA_GATEWAY_PAY_BY_INSTALMENTS_ID = 'tamara-gateway-pay-by-instalments',
        TAMARA_GATEWAY_PAY_IN_X = 'tamara-gateway-pay-in-',
        TAMARA_GATEWAY_PAY_IN_2 = 'tamara-gateway-pay-in-2',
        TAMARA_GATEWAY_PAY_IN_3 = 'tamara-gateway-pay-in-3',
        TAMARA_GATEWAY_PAY_IN_4 = 'tamara-gateway-pay-in-4',
        TAMARA_GATEWAY_PAY_IN_5 = 'tamara-gateway-pay-in-5',
        TAMARA_GATEWAY_PAY_IN_6 = 'tamara-gateway-pay-in-6',
        TAMARA_GATEWAY_PAY_IN_7 = 'tamara-gateway-pay-in-7',
        TAMARA_GATEWAY_PAY_IN_8 = 'tamara-gateway-pay-in-8',
        TAMARA_GATEWAY_PAY_IN_9 = 'tamara-gateway-pay-in-9',
        TAMARA_GATEWAY_PAY_IN_10 = 'tamara-gateway-pay-in-10',
        TAMARA_GATEWAY_PAY_IN_11 = 'tamara-gateway-pay-in-11',
        TAMARA_GATEWAY_PAY_IN_12 = 'tamara-gateway-pay-in-12',
        TAMARA_GATEWAY_CHECKOUT_ID = 'tamara-gateway-checkout',
        TAMARA_AUTHORISED_STATUS = 'authorised',
        TAMARA_CANCELED_STATUS = 'canceled',
        TAMARA_PARTIALLY_CAPTURED_STATUS = 'partially_captured',
        TAMARA_FULLY_CAPTURED_STATUS = 'fully_captured',
        TAMARA_PARTIALLY_REFUNDED_STATUS = 'partially_refunded',
        TAMARA_FULLY_REFUNDED_STATUS = 'fully_refunded',
        TAMARA_INLINE_TYPE_KNOWMORE_WIDGET_INT = 1,
        TAMARA_INLINE_TYPE_PRODUCT_WIDGET_INT = 2,
        TAMARA_INLINE_TYPE_CART_WIDGET_INT = 3,
        TAMARA_INLINE_TYPE_SINGLE_CHECKOUT_WIDGET = 6,
        DOWN_PAYMENT = 'down_payment',
        INSTALMENT = 'instalment',
        PAY_LATER_PDP_MAX_AMOUNT = 200;

    /**
     * @var string Version of this plugin
     */
    public $version;

    /** @noinspection PhpUnusedElementInspection */
    /**
     * @var string Base path to this plugin
     */
    public $basePath;

    /** @noinspection PhpUnusedElementInspection */
    /**
     * @var string Base url of the folder of this plugin
     */
    public $baseUrl;

    /**
     * @var string The filename of the plugin (it should have full path + file name)
     */
    public $pluginFilename;

    /**
     * @var \WP_REST_Request $restApiRequest
     */
    protected $restApiRequest;

    /**
     * @var string The customer phone number on checkout
     */
    protected $customerPhoneNumber;

    /**
     * Tamara_Checkout constructor.
     *
     * @param $config
     */
    public function __construct($config)
    {
        $this->bindConfig($config);

        // phpcs:ignore PSR2.ControlStructures.ControlStructureSpacing.SpacingAfterOpenBrace
        if (!empty($services = $config['services'] ?? null)) {
            $this->registerServices($services);
        }
    }

    /**
     * @param float $totalAmount
     * @param int $numberOfInstalments
     *
     * @return array
     */
    public static function calculateInstalmentPlan(float $totalAmount, int $numberOfInstalments = 3): array
    {
        $totalAmount = $totalAmount * 100;
        $modAmount = $totalAmount % $numberOfInstalments;
        $downPayment = round(floatval((($totalAmount - $modAmount) / $numberOfInstalments / 100) + ($modAmount / 100)), 2);
        $instalment = ($totalAmount - $modAmount) / $numberOfInstalments / 100;

        return [
            static::DOWN_PAYMENT => $downPayment,
            static::INSTALMENT => $instalment,
        ];
    }

    /**
     * Register service providers set in config
     *
     * @param $services
     */
    protected function registerServices($services)
    {
        foreach ($services as $serviceClassname => $serviceConfig) {
            $this->singleton(
                $serviceClassname,
                function ($container) use ($serviceClassname, $serviceConfig) {
                    $serviceInstance = new $serviceClassname();
                    if (method_exists($serviceInstance, 'bindConfig')) {
                        $serviceInstance->bindConfig($serviceConfig);
                    }

                    if (in_array(ServiceTrait::class, class_uses($serviceInstance))) {
                        $serviceInstance->setContainer($container);
                        $serviceInstance->init();
                    }

                    return $serviceInstance;
                }
            );
        }
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * @param string $alias
     *
     * @return mixed
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function getService($alias)
    {
        return $this->make($alias);
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Get the `view` service
     *
     * @return ViewService
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public static function getServiceView()
    {
        return static::getInstance()->getService(ViewService::class);
    }

    /**
     * @param $config
     *
     * @throws Exception
     */
    public static function initInstanceWithConfig($config)
    {
        if (is_null(static::$instance)) {
            static::setInstance(new static($config));
        }

        // phpcs:ignore PSR2.ControlStructures.ControlStructureSpacing.SpacingAfterOpenBrace
        if (!static::getInstance() instanceof static) {
            throw new Exception('No plugin initialized.');
        }
    }

    /**
     * Initialize all needed things for this plugin: hooks, assignments...
     */
    public function initPlugin(): void
    {
        add_action('init', [$this, 'checkWooCommerceExistence']);
        if (!class_exists('WooCommerce')) {
            return;
        }

        // Load text domain
        add_action('init', [$this, 'tamaraLoadTextDomain']);

        // Register new Tamara custom statuses
        add_action('init', [$this, 'registerTamaraCustomOrderStatuses']);

        // For Admin
        add_action('admin_enqueue_scripts', [$this, 'enqueueAdminSettingScripts']);

        // Handle refund when a refund is created
        add_action('woocommerce_create_refund', [$this, 'tamaraRefundPayment'], 10, 2);

        // Add Tamara custom statuses to wc order status list
        add_filter('wc_order_statuses', [$this, 'addTamaraCustomOrderStatuses']);

        // Add note on Refund
        add_action('woocommerce_order_item_add_action_buttons', [$this, 'addRefundNote']);

        add_filter('woocommerce_rest_prepare_shop_order_object', [$this, 'updateTamaraCheckoutDataToOrder'], 10, 3);

        add_action('init', [$this, 'addCustomRewriteRules']);
        add_action('init', [$this, 'addTamaraAuthoriseFailedMessage'], 1000);
        add_action('parse_request', [$this, 'handleTamaraApi'], 1000);
        add_action('wp_enqueue_scripts', [$this, 'enqueueScripts']);
//        add_filter('woocommerce_checkout_fields', [$this, 'adjustBillingPhoneDescription']);
        add_filter('woocommerce_payment_gateways', [$this, 'registerTamaraPaymentGateway']);
        add_filter('woocommerce_available_payment_gateways', [$this, 'adjustTamaraPaymentTypesOnCheckout'], 9998, 1);
        add_action('woocommerce_update_options_checkout_'.static::TAMARA_GATEWAY_ID, [$this, 'onSaveSettings'], 10, 1);
        add_action($this->getTamaraPopupWidgetPosition(), [$this, 'showTamaraProductPopupWidget']);
        add_action($this->getTamaraCartPopupWidgetPosition(), [$this, 'showTamaraCartProductPopupWidget']);
        add_action('wp_ajax_tamara_perform_cron', [$this, 'performCron']);
        add_action('wp_ajax_tamara-authorise', [$this, 'tamaraAuthoriseHandler']);
        add_action('wp_ajax_nopriv_tamara-authorise', [$this, 'tamaraAuthoriseHandler']);
        add_action('wp_head', [$this, 'addTamaraGeneratorMeta']);
        add_filter('script_loader_tag', [$this, 'addDeferToScriptTags'], 10, 3);
        add_action('woocommerce_checkout_update_order_review', [$this, 'getUpdatedPhoneNumberOnCheckout']);

        add_action('admin_footer', [$this, 'addCronJobTriggerScript']);

        add_shortcode('tamara_show_popup', [$this, 'tamaraProductPopupWidget']);
        add_shortcode('tamara_show_cart_popup', [$this, 'tamaraCartPopupWidget']);
        add_shortcode('tamara_authorise_order', [$this, 'doAuthoriseOrderAction']);

        // For Rest Api
        add_filter('rest_pre_dispatch', [$this, 'populateRestApiRequest'], 1, 3);

        // Update Settings Url in admin for Pay By Instalments
        add_action('admin_head', [$this, 'updatePayByInstalmentSettingUrl']);
        add_filter('woocommerce_billing_fields', [$this, 'forceRequireBillingPhone'], 1001, 2);

        add_action('wp_ajax_tamara-get-instalment-plan', [$this, 'getInstalmentPlanAccordingToProductVariation']);
        add_action('wp_ajax_nopriv_tamara-get-instalment-plan', [$this, 'getInstalmentPlanAccordingToProductVariation']);

        add_action('wp_ajax_update-tamara-checkout-params', [$this, 'updateTamaraCheckoutParams']);
        add_action('wp_ajax_nopriv_update-tamara-checkout-params', [$this, 'updateTamaraCheckoutParams']);

        add_action('wp_loaded', [$this, 'overrideWcClearCart'], 0);
        add_action('wp_loaded', [$this, 'cancelOrder'], 21);

        // Add Tamara Note on Order Received page
        add_filter('woocommerce_thankyou_order_received_text', [$this, 'tamaraOrderReceivedText'], 10, 2);

    }

    /**
     * Populate Rest Api Request
     *
     * @param mixed $result
     * @param \WP_REST_Server $restApiServer
     * @param \WP_REST_Request $restApiRequest
     *
     * @return mixed
     */
    public function populateRestApiRequest($result, $restApiServer, $restApiRequest)
    {
        $this->setRestApiRequest($restApiRequest);

        return $result;
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Add Tamara Note after successful payment
     *
     * @param string $str
     * @param \Automattic\WooCommerce\Admin\Overrides\Order $order
     *
     * @return string
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function tamaraOrderReceivedText($str, $order)
    {
        if (empty($order)) {
            return $str;
        }

        $payment_method = $order->get_payment_method();

        if (!empty($payment_method) && $this->isTamaraGateway($payment_method)) {
            $tamaraOrderReceivedHtml = $this->getServiceView()->render('views/woocommerce/checkout/tamara-order-received-button',
                [
                    'textDomain' => 'tamara-checkout',
                ]);

            return $str.$tamaraOrderReceivedHtml;
        }

        return $str;
    }

    /**
     * Handle Tamara log message
     *
     * @param string $message
     *
     */
    public function logMessage($message)
    {
        if ($this->isCustomLogMessageEnabled()) {
            if (is_array($message)) {
                $message = json_encode($message);
            }
            $fileHandle = fopen($this->logMessageFilePath(), "a");
            fwrite($fileHandle, "[".gmdate('Y-m-d h:i:s')."] ".$message."\n");
            fclose($fileHandle);
        }
    }

    /**
     * Update order status and add order note wrapper
     *
     * @param WC_Order $wcOrder
     * @param string $orderNote
     * @param string $newOrderStatus
     * @param string $updateOrderStatusNote
     *
     */
    public function updateOrderStatusAndAddOrderNote($wcOrder, $orderNote, $newOrderStatus, $updateOrderStatusNote)
    {
        if ($wcOrder) {
            $this->logMessage(sprintf("Tamara - Prepare to Update Order Status - Order ID: %s, Order Note: %s, new order status: %s, order status note: %s", $wcOrder->get_id(), $orderNote, $newOrderStatus, $updateOrderStatusNote));
            try {
                $wcOrder->add_order_note($orderNote);
                $wcOrder->update_status($newOrderStatus, $updateOrderStatusNote, true);
            } catch (Exception $exception) {
                $this->logMessage(sprintf("Tamara - Failed to Update Order Status - Order ID: %s, Order Note: %s, new order status: %s, order status note: %s. Error Message: %s", $wcOrder->get_id(), $orderNote, $newOrderStatus, $updateOrderStatusNote, $exception->getMessage()));
            }
        }
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Get WC Tamara Gateway Pay By Later class
     *
     * @return WCTamaraGateway
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function getWCTamaraGatewayService()
    {
        return $this->getService(WCTamaraGateway::class);
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Get WC Tamara Gateway Pay Now class
     *
     * @return WCTamaraGatewayPayNow
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function getWCTamaraGatewayPayNowService()
    {
        return $this->getService(WCTamaraGatewayPayNow::class);
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Get WC Tamara Gateway Pay By Instalments class
     *
     * @return WCTamaraGateway
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function getWCTamaraGatewayPayByInstalmentsService()
    {
        return $this->getService(WCTamaraGatewayPayByInstalments::class);
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Get WC Tamara Gateway Pay In X class
     *
     * @param $instalment
     *
     * @return WCTamaraGateway
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function getWCTamaraGatewayPayInXService($instalment)
    {
        $instalmentService = 'Tamara\Wp\Plugin\Services\WCTamaraGatewayPayIn'.$instalment;

        return $this->getService($instalmentService);
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Get WC Tamara Gateway Single Checkout class
     *
     * @return WCTamaraGateway
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function getWCTamaraGatewayCheckoutService()
    {
        return $this->getService(WCTamaraGatewayCheckout::class);
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Get WC Tamara Gateway Pay Next Month class
     *
     * @return WCTamaraGateway
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function getWCTamaraGatewayPayNextMonthService()
    {
        return $this->getService(WCTamaraGatewayPayNextMonth::class);
    }

    /**
     * Get Tamara Popup Widget postion
     */
    public function getTamaraPopupWidgetPosition()
    {
        return $this->getWCTamaraGatewayOptions()['popup_widget_position'] ?? 'woocommerce_before_add_to_cart_form';
    }

    /**
     * Get Tamara Cart Popup Widget postion
     */
    public function getTamaraCartPopupWidgetPosition()
    {
        return $this->getWCTamaraGatewayOptions()['cart_popup_widget_position'] ?? 'woocommerce_proceed_to_checkout';
    }

    /**
     * Check if Payment type Pay By Later is enabled in admin settings
     */
    public function isPayByLaterEnabled()
    {
        return 'yes' === ($this->getWCTamaraGatewayOptions()['pay_by_later_enabled'] ?? 'no');
    }

    /**
     * Check if Payment type Pay Now is enabled in admin settings
     */
    public function isPayNowEnabled()
    {
        return 'yes' === ($this->getWCTamaraGatewayOptions()['pay_now_enabled'] ?? 'no');
    }

    /**
     * Check if Payment type Pay By Instalments is enabled in admin settings
     */
    public function isPayByInstalmentsEnabled()
    {
        return 'yes' === ($this->getWCTamaraGatewayOptions()['pay_by_instalments_enabled'] ?? 'no');
    }

    /**
     * Check if a specific Pay In X payment type is enabled in admin settings
     *
     * @param $instalment
     * @param $countryCode
     *
     * @return bool
     */
    public function isPayInXEnabled($instalment, $countryCode)
    {
        return 'yes' === ($this->getWCTamaraGatewayOptions()['pay_in_'.$instalment.'_'.$countryCode] ?? 'no');
    }

    /**
     * Check if Tamara Gateway is enabled in admin settings
     */
    public function isTamaraGatewayEnabled()
    {
        return 'yes' === ($this->getWCTamaraGatewayOptions()['enabled'] ?? 'no');
    }

    /**
     * Check if Tamara custom log message is enabled in admin settings
     */
    public function isCustomLogMessageEnabled()
    {
        return 'yes' === ($this->getWCTamaraGatewayOptions()['custom_log_message_enabled'] ?? 'no');
    }

    /**
     * Check if Tamara force billing phone option is enabled in admin settings
     */
    public function isForceBillingPhoneEnabled()
    {
        return 'yes' === ($this->getWCTamaraGatewayOptions()['force_billing_phone'] ?? 'no');
    }

    /**
     * Check if Cronjob is enabled in admin settings
     */
    public function isCronjobEnabled()
    {
        return 'yes' === ($this->getWCTamaraGatewayOptions()['crobjob_enabled'] ?? 'no');
    }

    /**
     * Check if Tamara Pay Later popup widget is enabled in admin settings
     */
    public function isPayLaterPDPEnabled()
    {
        return 'yes' === ($this->getWCTamaraGatewayOptions()['pay_later_popup_widget_enabled'] ?? 'no');
    }

    /**
     * Check if Always Show Popup Widget is enabled in admin settings
     */
    public function isAlwaysShowWidgetPopupEnabled()
    {
        return 'yes' === ($this->getWCTamaraGatewayOptions()['always_show_popup_widget_enabled'] ?? 'no');
    }

    /**
     * Check if Showing Popup Widget is disabled in admin settings
     */
    public function isWidgetPopupDisabled()
    {
        return 'yes' === ($this->getWCTamaraGatewayOptions()['popup_widget_disabled'] ?? 'no');
    }

    /**
     * Check if Showing Popup Widget in Cart page is disabled in admin settings
     */
    public function isCartWidgetPopupDisabled()
    {
        return 'yes' === ($this->getWCTamaraGatewayOptions()['cart_popup_widget_disabled'] ?? 'no');
    }

    /**
     * Check if Credit Precheck is enabled in admin settings
     */
    public function isCreditPrecheckEnabled()
    {
        return 'yes' === ($this->getWCTamaraGatewayOptions()['credit_precheck_enabled'] ?? 'no');
    }

    /**
     * Get WC Tamara Gateway options
     */
    public function getWCTamaraGatewayOptions()
    {
        return get_option($this->getWCTamaraGatewayOptionKey(), null);
    }

    /**
     * Get WC Tamara Gateway options
     */
    public function getWCTamaraGatewayOptionKey()
    {
        return 'woocommerce_'.static::TAMARA_GATEWAY_ID.'_settings';
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Get on save settings method from WC Tamara Gateway
     *
     * @param $settings
     *
     * @return void
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function onSaveSettings($settings)
    {
        return $this->getWCTamaraGatewayService()->onSaveSettings($settings);
    }

    /**
     * Tamara Log File Path
     */
    public function logMessageFilePath()
    {
        $upload_dir = wp_upload_dir();
        $plugin_dir = $upload_dir['basedir'] . '/tamara-checkout';
        if ( ! file_exists( $plugin_dir ) ) {
            wp_mkdir_p( $plugin_dir );
        }
        return $plugin_dir . '/' . static::MESSAGE_LOG_FILE_NAME;
    }

    /**
     * Tamara Log File Url
     */
    public function logMessageFileUrl()
    {
        return wp_upload_dir()['baseurl'].'/'.static::MESSAGE_LOG_FILE_NAME;
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Force pending capture payments within 180 days to be captured
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function forceCaptureTamaraOrder()
    {
        $tamaraCapturePaymentStatus = $this->getWCTamaraGatewayService()->tamaraStatus['payment_capture'] ?? 'wc-completed';
        $customerOrders = [
            'fields' => 'ids',
            'post_type' => 'shop_order',
            'post_status' => $tamaraCapturePaymentStatus,
            'date_query' => [
                'before' => date('Y-m-d', strtotime('-14 days')),
                'after' => date('Y-m-d', strtotime('-180 days')),
                'inclusive' => true,
            ],
            'meta_query' => [
                'relation' => 'AND',
                [
                    'key' => '_tamara_order_id',
                    'compare' => 'EXISTS',
                ],
                [
                    'key' => '_tamara_capture_id',
                    'compare' => 'NOT EXISTS',
                ],
				[
                    'key' => '_tamara_force_capture_checked',
                    'compare' => 'NOT EXISTS',
                ],
            ],
        ];

        $customerOrdersQuery = new \WP_Query($customerOrders);

        $wcOrderIds = $customerOrdersQuery->posts;

        foreach ($wcOrderIds as $wcOrderId) {
			update_post_meta($wcOrderId, '_tamara_force_capture_checked', 1);

            if (static::TAMARA_FULLY_CAPTURED_STATUS === TamaraCheckout::getInstance()->getTamaraOrderStatus($wcOrderId)) {
                $tamaraCaptureId = $this->getWCTamaraGatewayService()->getTamaraCaptureId($wcOrderId);
				update_post_meta($wcOrderId, '_tamara_capture_id', $tamaraCaptureId);

                return true;
            } else {
                $this->getWCTamaraGatewayService()->captureWcOrder($wcOrderId);
            }
        }
    }

    /**
     * Force pending authorise payments within 180 days to be authorised
     *
     */
    public function forceAuthoriseTamaraOrder()
    {
        $toAuthoriseStatus = 'wc-pending';
        $customerOrders = [
            'fields' => 'ids',
            'post_type' => 'shop_order',
            'post_status' => $toAuthoriseStatus,
            'date_query' => [
                'before' => date('Y-m-d', strtotime('-1 second')),
                'after' => date('Y-m-d', strtotime('-180 days')),
                'inclusive' => true,
            ],
            'meta_query' => [
                'relation' => 'AND',
                [
                    'key' => '_tamara_checkout_session_id',
                    'compare' => 'EXISTS',
                ],
                [
                    'key' => '_tamara_order_id',
                    'compare' => 'NOT EXISTS',
                ],
				[
                    'key' => '_tamara_force_authorise_checked',
                    'compare' => 'NOT EXISTS',
                ],
            ],
        ];

        $customerOrdersQuery = new \WP_Query($customerOrders);

        $wcOrderIds = $customerOrdersQuery->posts;

        foreach ($wcOrderIds as $wcOrderId) {
			update_post_meta($wcOrderId, '_tamara_force_authorise_checked', 1);
            if (!$this->isOrderAuthorised($wcOrderId)) {
                $this->authoriseOrder($wcOrderId);
            }
        }
    }

    /**
     * Add Tamara Refund Note
     *
     * @param WC_Order $order
     */
    public function addRefundNote($order)
    {
        if ($this->isTamaraGateway($order->get_payment_method())) {
            echo '<br>' . esc_html(__('This order is paid via Tamara Pay Later.', 'tamara-checkout'));
            echo '<br>' . '<strong>' . esc_html(__('You need to refund the full shipping amount.',
                    'tamara-checkout')) . '</strong>';
        }
    }

    /**
     * Register Tamara new statuses
     */
    public function registerTamaraCustomOrderStatuses()
    {
        register_post_status('wc-tamara-p-canceled', [
            'label' => _x('Tamara Payment Cancelled', 'Order status', 'tamara-checkout'),
            'public' => true,
            'exclude_from_search' => false,
            'show_in_admin_all_list' => true,
            'show_in_admin_status_list' => true,
            // translators: %s: Number of orders
            'label_count' => _n_noop('Tamara Payment Cancelled <span class="count">(%s)</span>',
                'Tamara Payment Cancelled <span class="count">(%s)</span>', 'tamara-checkout'),
        ]);

        register_post_status('wc-tamara-p-failed', [
            'label' => _x('Tamara Payment Failed', 'Order status', 'tamara-checkout'),
            'public' => true,
            'exclude_from_search' => false,
            'show_in_admin_all_list' => true,
            'show_in_admin_status_list' => true,
            // translators: %s: Number of orders
            'label_count' => _n_noop('Tamara Payment Failed <span class="count">(%s)</span>',
                'Tamara Payment Failed <span class="count">(%s)</span>', 'tamara-checkout'),
        ]);

        register_post_status('wc-tamara-c-failed', [
            'label' => _x('Tamara Capture Failed', 'Order status', 'tamara-checkout'),
            'public' => true,
            'exclude_from_search' => false,
            'show_in_admin_all_list' => true,
            'show_in_admin_status_list' => true,
            // translators: %s: Number of orders
            'label_count' => _n_noop('Tamara Capture Failed <span class="count">(%s)</span>',
                'Tamara Capture Failed <span class="count">(%s)</span>', 'tamara-checkout'),
        ]);

        register_post_status('wc-tamara-a-done', [
            'label' => _x('Tamara Authorise Success', 'Order status', 'tamara-checkout'),
            'public' => true,
            'exclude_from_search' => false,
            'show_in_admin_all_list' => true,
            'show_in_admin_status_list' => true,
            // translators: %s: Number of orders
            'label_count' => _n_noop('Tamara Authorise Success <span class="count">(%s)</span>',
                'Tamara Authorise Success <span class="count">(%s)</span>', 'tamara-checkout'),
        ]);

        register_post_status('wc-tamara-a-failed', [
            'label' => _x('Tamara Authorise Failed', 'Order status', 'tamara-checkout'),
            'public' => true,
            'exclude_from_search' => false,
            'show_in_admin_all_list' => true,
            'show_in_admin_status_list' => true,
            // translators: %s: Number of orders
            'label_count' => _n_noop('Tamara Authorise Failed <span class="count">(%s)</span>',
                'Tamara Authorise Failed <span class="count">(%s)</span>', 'tamara-checkout'),
        ]);

        register_post_status('wc-tamara-o-canceled', [
            'label' => _x('Tamara Order Cancelled', 'Order status', 'tamara-checkout'),
            'public' => true,
            'exclude_from_search' => false,
            'show_in_admin_all_list' => true,
            'show_in_admin_status_list' => true,
            // translators: %s: Number of orders
            'label_count' => _n_noop('Tamara Order Cancelled <span class="count">(%s)</span>',
                'Tamara Order Cancelled <span class="count">(%s)</span>', 'tamara-checkout'),
        ]);

        register_post_status('wc-tamara-p-capture', [
            'label' => _x('Tamara Payment Capture', 'Order status', 'tamara-checkout'),
            'public' => true,
            'exclude_from_search' => false,
            'show_in_admin_all_list' => true,
            'show_in_admin_status_list' => true,
            // translators: %s: Number of orders
            'label_count' => _n_noop('Tamara Payment Capture <span class="count">(%s)</span>',
                'Tamara Payment Capture <span class="count">(%s)</span>', 'tamara-checkout'),
        ]);
    }

    /**
     * Add Tamara Statuses to the list of WC Order statuses
     *
     * @param array $order_statuses
     *
     * @return array $order_statuses
     */
    public function addTamaraCustomOrderStatuses($order_statuses)
    {
        $order_statuses['wc-tamara-p-canceled'] = _x('Tamara Payment Cancelled', 'Order status',
            'tamara-checkout');
        $order_statuses['wc-tamara-p-failed'] = _x('Tamara Payment Failed', 'Order status',
            'tamara-checkout');
        $order_statuses['wc-tamara-c-failed'] = _x('Tamara Capture Failed', 'Order status',
            'tamara-checkout');
        $order_statuses['wc-tamara-a-done'] = _x('Tamara Authorise Done', 'Order status',
            'tamara-checkout');
        $order_statuses['wc-tamara-a-failed'] = _x('Tamara Authorise Failed', 'Order status',
            'tamara-checkout');
        $order_statuses['wc-tamara-o-canceled'] = _x('Tamara Order Cancelled', 'Order status',
            'tamara-checkout');
        $order_statuses['wc-tamara-p-capture'] = _x('Tamara Payment Capture', 'Order status',
            'tamara-checkout');

        return $order_statuses;
    }

    /**
     * Localize the plugin
     */
    public function tamaraLoadTextDomain()
    {
        load_plugin_textdomain(
            'tamara-checkout',
            false,
            dirname(plugin_basename($this->pluginFilename)).'/languages'
        );
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Handle process for Tamara endpoint slug returned
     *
     * @param WP $wp
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function handleTamaraApi($wp)
    {
        $pagename = $wp->query_vars['pagename'] ?? null;
        $tamaraPageSlugs = [
            WCTamaraGateway::IPN_SLUG,
            WCTamaraGateway::WEBHOOK_SLUG,
            WCTamaraGateway::PAYMENT_SUCCESS_SLUG,
            WCTamaraGateway::PAYMENT_CANCEL_SLUG,
            WCTamaraGateway::PAYMENT_FAIL_SLUG,
        ];
        if (in_array($pagename, $tamaraPageSlugs)) {
            $this->logMessage(sprintf('Pagename: %s', $pagename));
        }

        if (WCTamaraGateway::IPN_SLUG === $pagename) {
            /** @var TamaraNotificationService $tamara_notification_service */
            $tamara_notification_service = $this->getService(TamaraNotificationService::class);
            $tamara_notification_service->handleIpnRequest();
            exit;
        } // Handle webhook
        elseif (WCTamaraGateway::WEBHOOK_SLUG === $pagename) {
            /** @var TamaraNotificationService $tamara_notification_service */
            $tamara_notification_service = $this->getService(TamaraNotificationService::class);
            $tamara_notification_service->handleWebhook();
            exit;
        } elseif (WCTamaraGateway::PAYMENT_CANCEL_SLUG === $pagename) {
            $this->handleTamaraCancelUrl();
            do_action('after_tamara_cancel');
            exit;
        } elseif (WCTamaraGateway::PAYMENT_FAIL_SLUG === $pagename) {
            $this->handleTamaraFailureUrl();
            do_action('after_tamara_failure');
            exit;
        }
    }

    /**
     * Detect if an order is authorised or not
     *
     * @param $wcOrderId
     *
     * @return bool
     */
    public function isOrderAuthorised($wcOrderId)
    {
        return !!get_post_meta($wcOrderId, 'tamara_authorized', true);
    }

    /**
     * Prevent an order is cancelled from FE if its payment has been authorised from Tamara
     *
     * @param WC_Order $wcOrder
     * @param int $wcOrderId
     *
     */
    protected function preventOrderCancelAction($wcOrder, $wcOrderId)
    {
        $orderNote = 'This order can not be cancelled because the payment was authorised from Tamara. Order ID: '.$wcOrderId;
        $wcOrder->add_order_note($orderNote);
        $this->logMessage($orderNote);
        wp_redirect(wc_get_cart_url());
    }

    /**
     * Output Tamara Checkout generator meta tag in document head.
     */
    public function addTamaraGeneratorMeta()
    {
        echo '<meta name="generator" content="TamaraCheckout '.esc_attr($this->version).'" />'."\n";
    }

    /**
     * Add defer attribute to Tamara summary widget script tag.
     *
     * @param string $tag
     * @param string $handle
     * @param string $src
     *
     * @return string
     */
    public function addDeferToScriptTags($tag, $handle, $src)
    {
        if ('tamara-summary-widget' === $handle) {
            return str_replace('<script ', '<script defer ', $tag);
        }

        return $tag;
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Detect if payment for WC order has been approved from Tamara
     *
     * @param int $wcOrderId
     *
     * @return bool
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    protected function isOrderTamaraApproved($wcOrderId)
    {
        $tamaraOrder = $this->getTamaraOrderByWcOrderId($wcOrderId);
        if ($tamaraOrder && ('approved' === $tamaraOrder->getStatus() || 'authorized' === $tamaraOrder->getStatus())) {
            return true;
        }

        return false;
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Get Tamara order id by WC order Id
     *
     * @param int $wcOrderId
     *
     * @return string
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    protected function getTamaraOrderId($wcOrderId)
    {
        $tamaraOrder = $this->getTamaraOrderByWcOrderId($wcOrderId);
        if ($tamaraOrder) {
            return $tamaraOrder->getOrderId();
        }

        return null;
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Get Tamara order by WC order Id
     *
     * @param int $wcOrderId
     *
     * @return null|Dependencies\Tamara\Response\Order\GetOrderByReferenceIdResponse
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function getTamaraOrderByWcOrderId($wcOrderId)
    {
        $tamaraClient = $this->getWCTamaraGatewayService()->tamaraClient;
        try {
            $tamaraOrderResponse = $tamaraClient->getOrderByReferenceId(new GetOrderByReferenceIdRequest($wcOrderId));
            $this->logMessage(sprintf("Tamara Get Order by Reference ID Response: %s", print_r($tamaraOrderResponse, true)));
            if ($tamaraOrderResponse->isSuccess()) {
                return $tamaraOrderResponse;
            }
        } catch (Exception $tamaraOrderResponseException) {
            $this->logMessage(
                sprintf(
                    "Tamara Get Order by Reference ID Failed Response.\nError message: ' %s'.\nTrace: %s",
                    $tamaraOrderResponseException->getMessage(),
                    $tamaraOrderResponseException->getTraceAsString()
                )
            );
        }

        return null;
    }

    /**
     * If the order is not authorised from Tamara, do it on the Tamara Success Url returned
     */
    public function tamaraAuthoriseHandler()
    {
        $wcOrderId = filter_input(INPUT_POST, 'wcOrderId', FILTER_SANITIZE_NUMBER_INT);
        $authoriseSuccessResponse = [
            'message' => 'authorise_success',
        ];

        if ($this->isOrderAuthorised($wcOrderId) || $this->authoriseOrder($wcOrderId)) {
            wp_send_json($authoriseSuccessResponse);
        }

        wp_send_json(
            [
                'message' => 'authorise_failed',
            ]
        );
    }

    /**
     * Do authorise order with order id from payload returning from Tamara
     */
    public function doAuthoriseOrderAction()
    {
        $wcOrderId = filter_input(INPUT_GET, 'wcOrderId', FILTER_SANITIZE_NUMBER_INT);
        $wcOrderId || $wcOrderId = filter_input(INPUT_POST, 'wcOrderId', FILTER_SANITIZE_NUMBER_INT);

        $this->authoriseOrder($wcOrderId);
    }

    /**
     * @param $wcOrderId
     *
     * @return bool true if an authorise action is made successfully, false if failed
     * or already authorised
     */
    public function authoriseOrder($wcOrderId)
    {
        /** @var WC_Order $wcOrder */
        $wcOrder = wc_get_order($wcOrderId);
        
        try {
            if (!$this->isOrderAuthorised($wcOrderId) && $wcOrder && $wcOrder->get_status() === 'pending') {
                $tamaraOrderId = (string) $this->getTamaraOrderId($wcOrderId);
                if (empty($tamaraOrderId)) {
                    return false;
                }

                /** @var TamaraNotificationService $tamaraNotificationService */
                $tamaraNotificationService = $this->getService(TamaraNotificationService::class);
                $tamaraNotificationService->authoriseOrder($wcOrderId, $tamaraOrderId);

                if ($this->isOrderAuthorised($wcOrderId)) {
                    return true;
                }
            }
        } catch (Exception $exception) {
        }

        return false;
    }

    /**
     * Add Tamara Authorise Failed Message on cart page
     */
    public function addTamaraAuthoriseFailedMessage()
    {
        $tamaraAuthoriseParam = isset($_GET['tamara_authorise']) ? sanitize_text_field(wp_unslash($_GET['tamara_authorise'])) : '';
        if ('failed' === $tamaraAuthoriseParam && !static::isRestRequest()) {
            if (function_exists('wc_add_notice')) {
                wc_add_notice(__('We are unable to authorise your payment from Tamara. Please contact us if you need assistance.', 'tamara-checkout'), 'error');
            }
        }
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Do needed things on Tamara Cancel Url returned
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function handleTamaraCancelUrl()
    {
        $orderId = filter_input(INPUT_GET, 'wcOrderId', FILTER_SANITIZE_NUMBER_INT);
        $wcOrder = wc_get_order($orderId);
        if ($this->isOrderAuthorised($orderId)) {
            $this->preventOrderCancelAction($wcOrder, $orderId);
        } elseif (!empty($orderId)) {
            $newOrderStatus = $this->getWCTamaraGatewayService()->tamaraStatus['payment_cancelled'];
            $orderNote = 'The payment for this order has been cancelled from Tamara.';
            $this->updateOrderStatusAndAddOrderNote($wcOrder, $orderNote, $newOrderStatus, '');
            $cancelUrlFromTamara = add_query_arg(
                [
                    'tamara_custom_status' => 'tamara-p-canceled',
                    'redirect_from' => 'tamara',
                    'cancel_order' => 'true',
                    'order' => $wcOrder->get_order_key(),
                    'order_id' => $orderId,
                    '_wpnonce' => wp_create_nonce('woocommerce-cancel_order'),
                ],
                $wcOrder->get_cancel_order_url_raw()
            );
            wp_redirect($cancelUrlFromTamara);
        }
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Do needed things on Tamara Failure Url returned
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function handleTamaraFailureUrl()
    {
        $orderId = filter_input(INPUT_GET, 'wcOrderId', FILTER_SANITIZE_NUMBER_INT);
        $wcOrder = wc_get_order($orderId);
        if ($this->isOrderAuthorised($orderId)) {
            $this->preventOrderCancelAction($wcOrder, $orderId);
        } elseif (!empty($orderId)) {
            $newOrderStatus = $this->getWCTamaraGatewayService()->tamaraStatus['payment_failed'];
            $orderNote = 'The payment for this order has been declined from Tamara.';
            $this->updateOrderStatusAndAddOrderNote($wcOrder, $orderNote, $newOrderStatus, '');
            $failureUrlFromTamara = add_query_arg(
                [
                    'tamara_custom_status' => 'tamara-p-failed',
                    'redirect_from' => 'tamara',
                    'cancel_order' => 'true',
                    'order' => $wcOrder->get_order_key(),
                    'order_id' => $orderId,
                    '_wpnonce' => wp_create_nonce('woocommerce-cancel_order'),
                ],
                $wcOrder->get_cancel_order_url_raw()
            );
            wp_redirect($failureUrlFromTamara);
        }
    }

    /**
     * Do some needed things when activate plugin
     */
    public function activatePlugin()
    {
        if (!class_exists('WooCommerce')) {
            die(sprintf(__('Plugin `%s` needs Woocommerce to be activated', 'tamara-checkout'),
                'Tamara Checkout'));
        }
    }

    /**
     * @noinspection PhpUnusedDeclarationInspection
     */
    public function deactivatePlugin()
    {
        // The problem with calling flush_rewrite_rules() is that the rules instantly get regenerated, while your plugin's hooks are still active.
        delete_option('rewrite_rules');
    }

    /**
     * Add rewrite rule for Tamara IPN and Webhook response page
     */
    public function addCustomRewriteRules()
    {
        add_rewrite_rule(WCTamaraGateway::IPN_SLUG.'/?$', 'index.php?pagename='.WCTamaraGateway::IPN_SLUG, 'top');
        add_rewrite_rule(WCTamaraGateway::WEBHOOK_SLUG.'/?$', 'index.php?pagename='.WCTamaraGateway::WEBHOOK_SLUG, 'top');
        add_rewrite_rule(WCTamaraGateway::PAYMENT_SUCCESS_SLUG.'/?$', 'index.php?pagename='.WCTamaraGateway::PAYMENT_SUCCESS_SLUG, 'top');
        add_rewrite_rule(WCTamaraGateway::PAYMENT_CANCEL_SLUG.'/?$', 'index.php?pagename='.WCTamaraGateway::PAYMENT_CANCEL_SLUG, 'top');
        add_rewrite_rule(WCTamaraGateway::PAYMENT_FAIL_SLUG.'/?$', 'index.php?pagename='.WCTamaraGateway::PAYMENT_FAIL_SLUG, 'top');
    }

    /**
     * Run this method under the "init" action
     */
    public function checkWooCommerceExistence()
    {
        if (class_exists('WooCommerce')) {
            // Add "Settings" link when the plugin is active
            add_filter('plugin_action_links_tamara-checkout/tamara-checkout.php', [$this, 'addSettingsLinks']);
        } else {
            require_once(ABSPATH.'wp-admin/includes/plugin.php');
            // Throw a notice if WooCommerce is NOT active
            deactivate_plugins(plugin_basename($this->pluginFilename));
            add_action('admin_notices', [$this, 'noticeNonWooCommerce']);
        }
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Add more links to plugin settings
     *
     * @param $pluginLinks
     *
     * @return array
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function addSettingsLinks($pluginLinks)
    {
        $pluginLinks[] = '<a href="'.$this->getAdminSettingLink().'">'.esc_html__('Settings',
                'tamara-checkout').'</a>';

        return $pluginLinks;
    }

    /**
     * Throw a notice if WooCommerce is NOT active
     */
    public function noticeNonWooCommerce()
    {
        $class = 'notice notice-warning';

        // translators: %s: Plugin name
        $message = sprintf(esc_html__('Plugin `%s` deactivated because WooCommerce is not active. Please activate WooCommerce first.',
            'tamara-checkout'), esc_html('Tamara Checkout'));

        printf('<div class="%1$s"><p><strong>%2$s</strong></p></div>', $class, $message);
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Add Tamara Payment Gateway
     *
     * @param $gateways
     *
     * @return array
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function registerTamaraPaymentGateway($gateways)
    {
        $gateways[] = $this->getWCTamaraGatewayService();

        return $gateways;
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Adjust Tamara payment types on checkout page based on Tamara settings
     *
     * @param $availableGateways
     *
     * @return array
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function adjustTamaraPaymentTypesOnCheckout($availableGateways)
    {
        if (!$this->isTamaraGatewayEnabled() || !is_checkout()) {
            return $availableGateways;
        }

        return array_filter($availableGateways, function ($gateway, $gatewayId) {
            if ('tamara-gateway' === $gatewayId) {
                return true;
            }

            if (is_string($gatewayId) && 0 === strpos($gatewayId, 'tamara-gateway')) {
                return false;
            }

            if (!empty($gateway->id) && 0 === strpos($gateway->id, 'tamara-gateway') && TamaraCheckout::TAMARA_GATEWAY_ID !== $gateway->id) {
                return false;
            }

            return true;
        }, ARRAY_FILTER_USE_BOTH);
    }

    /**
     * Enqueue admin scripts for settings
     */
    public function enqueueAdminSettingScripts()
    {
        // Only enqueue the setting scripts on the Tamara Checkout settings screen.
        if ($this->isTamaraAdminSettingsScreen()) {
            wp_enqueue_script('tamara-checkout-settings-js', $this->baseUrl.'/assets/dist/js/admin.js', ['jquery'],
                $this->version, true);
            wp_enqueue_style('tamara-admin-css', $this->baseUrl.'/assets/dist/css/admin.css', [],
                $this->version);
        } // Load the admin stylesheet on shop order screen
        elseif (isset($_GET['post_type']) && ('shop_order' === $_GET['post_type'])) {
            wp_enqueue_style('tamara-admin-css', $this->baseUrl.'/assets/dist/css/admin.css', [],
                $this->version);
        }
    }

    /**
     * Add some help text for billing phone when using Tamara payment
     *
     * @param $checkoutFields
     *
     * @return mixed
     */
    public function adjustBillingPhoneDescription($checkoutFields)
    {
        if (isset($checkoutFields['billing'], $checkoutFields['billing']['billing_phone'])) {
            $checkoutFields['billing']['billing_phone']['description'] = __('If you use Tamara Payment, this should be your full Tamara registered phone number (e.g. +966504449999 for KSA, +97150888444 for UAE)',
                'tamara-checkout');
        }

        return $checkoutFields;
    }

    /**
     * Enqueue FE stylesheet and scripts
     */
    public function enqueueScripts()
    {
        $storeCurrency = esc_js(get_woocommerce_currency());
        $publicKey = esc_js($this->getWCTamaraGatewayService()->getPublicKey() ?? '');
        $siteLocale = esc_js(substr(get_locale(), 0, 2) ?: 'en');
        $countryCode = esc_js($this->getWCTamaraGatewayService()->getCurrentCountryCode());
        $ajaxUrl = esc_js(admin_url('admin-ajax.php'));

        $summaryWidgetUrl = $this->getWCTamaraGatewayService()->isLiveMode()
            ? static::TAMARA_SUMMARY_WIDGET_URL
            : static::TAMARA_SUMMARY_WIDGET_SANDBOX_URL;

        wp_enqueue_script('tamara-summary-widget', $summaryWidgetUrl, [], $this->version, false);

        $inlineScript = sprintf(
            'let tamaraCheckoutParams = {"ajaxUrl":"%s","publicKey":"%s","currency":"%s","country":"%s"}; window.tamaraWidgetConfig = {"lang":"%s","country":"%s","publicKey":"%s"};',
            $ajaxUrl,
            $publicKey,
            $storeCurrency,
            $countryCode,
            $siteLocale,
            $countryCode,
            $publicKey
        );
        wp_add_inline_script('tamara-summary-widget', $inlineScript, 'before');

        wp_enqueue_style('tamara-checkout', $this->baseUrl.'/assets/dist/css/main.css', [], $this->version . '&' . time());
        wp_enqueue_script('tamara-checkout', $this->baseUrl.'/assets/dist/js/main.js', ['jquery'], $this->version . '&' . time(), true);
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Add relevant links to plugins page
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function getAdminSettingLink()
    {
        if (version_compare(WC()->version, '2.6', '>=')) {
            $sectionSlug = $this->getWCTamaraGatewayService()->id;
        } else {
            $sectionSlug = strtolower(WCTamaraGateway::class);
        }

        return admin_url('admin.php?page=wc-settings&tab=checkout&section='.$sectionSlug);
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * @param \WC_Order_Refund $wcOrderRefund
     * @param $args
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     * @throws Exception
     */
    public function tamaraRefundPayment($wcOrderRefund, $args)
    {
        $wcOrder = wc_get_order($args['order_id']);
        $wcOrderId = $args['order_id'];
        $payment_method = $wcOrder->get_payment_method();

        if ($this->isTamaraGateway($payment_method)) {
            $tamaraOrderId = $this->getWCTamaraGatewayService()->getTamaraOrderId($wcOrderId);
            $captureId = $this->getWCTamaraGatewayService()->getTamaraCaptureId($wcOrderId);
            $refundCollection = [];
            $wcOrderTotal = new Money(MoneyHelper::formatNumber(abs($wcOrderRefund->get_amount())),
                $wcOrder->get_currency());
            $wcShippingTotal = new Money(MoneyHelper::formatNumber(abs($wcOrderRefund->get_shipping_total())),
                $wcOrder->get_currency());
            $wcTaxTotal = new Money(MoneyHelper::formatNumber(abs($wcOrderRefund->get_total_tax())),
                $wcOrder->get_currency());
            $wcDiscountTotal = new Money(MoneyHelper::formatNumber($wcOrderRefund->get_discount_total()),
                $wcOrder->get_currency());
            $wcOrderItemsRefund = $this->getWCTamaraGatewayService()->populateTamaraRefundOrderItems($wcOrderRefund);

            try {
                $refundItem = new Refund($captureId, $wcOrderTotal, $wcShippingTotal, $wcTaxTotal,
                    $wcDiscountTotal,
                    $wcOrderItemsRefund);
                array_push($refundCollection, $refundItem);
                $refundResponse = $this->getWCTamaraGatewayService()->tamaraClient->refund(new RefundRequest($tamaraOrderId,
                    $refundCollection));
                $this->logMessage(sprintf("Tamara Refund Response Data: %s", print_r($refundResponse, true)));
            } catch (Exception $tamaraRefundException) {
                $this->logMessage(sprintf("Tamara Service timeout or disconnected.\nError message: '%s'.\nTrace: %s",
                    $tamaraRefundException->getMessage(), $tamaraRefundException->getTraceAsString()));
            }

            if (isset($refundResponse) && $refundResponse->isSuccess()) {
                $wcOrder->add_order_note(
                /* translators: Refund ID */
                    sprintf(__('Order has been refunded successfully - Refund ID: #%1$s', 'tamara-checkout'),
                        $wcOrderRefund->get_id()));

            } else {
                $errorMessage = null;

                if (isset($tamaraRefundException) && $tamaraRefundException instanceof Exception) {

                    $errorMessage = $tamaraRefundException->getMessage();
                    $this->logMessage($errorMessage);

                } elseif (isset($refundResponse)) {
                    if ('refund.shipping_amount_invalid' === $refundResponse->getMessage()) {
                        throw new Exception(__('You need to enter the full shipping amount to refund.',
                            'tamara-checkout'));
                    } elseif ('items_is_empty' === $refundResponse->getErrors()[0]['error_code']) {
                        throw new Exception(__('Refund item is empty. Please choose your item to refund.',
                            'tamara-checkout'));
                    } elseif ('refund.capture_not_found' === $refundResponse->getMessage()) {
                        $captureNotFoundMessage = __('Tamara Capture ID not found. Please capture the payment before making a refund.',
                            'tamara-checkout');
                        $wcOrder->add_order_note($captureNotFoundMessage);
                        throw new Exception($captureNotFoundMessage);
                    }
                }
                throw new Exception(__('Error! Tamara is having a problem. Please contact Tamara and try again later',
                    'tamara-checkout'));
            }
        }
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Tamara show widget popup shortcode callback method
     *
     * @param $attributes
     *
     * @return bool|string|void|null
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function tamaraProductPopupWidget($attributes)
    {
		extract(shortcode_atts(array(
            'price' => '',
            'currency' => '',
            'language' => '',
        ), $attributes));
        $dataPrice = !empty($price) ? $price : $this->getDisplayedProductPrice();
        $dataCurrency = !empty($currency) ? $currency : get_woocommerce_currency();
        $dataLanguage = !empty($language) ? $language : substr(get_locale(), 0, 2);
        if ($this->isWidgetPopupDisabled() ||
            (!empty($this->getDisplayedProductId()) && $this->isExcludedProduct($this->getDisplayedProductId())) ||
            (!empty($this->getDisplayedProductCategoryIds())
             && $this->isExcludedProductCategory($this->getDisplayedProductCategoryIds()))) {
            return false;
        } else {
			$itemPrice = is_array($dataPrice) ? $this->getAppropriateVariationProductPrice($dataPrice) : $dataPrice;
            return $this->getServiceView()->render('views/woocommerce/checkout/tamara-popup-widget',
                [
                    'dataPrice' => $itemPrice ?? 0,
                    'dataCurrency' => $dataCurrency,
                    'dataLanguage' => $dataLanguage ?? 'en',
                    'inlineType' => static::TAMARA_INLINE_TYPE_PRODUCT_WIDGET_INT,
                ]);
        }
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Tamara show cart widget popup shortcode callback method
     *
     * @param $attributes
     *
     * @return bool|string|void|null
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function tamaraCartPopupWidget($attributes)
    {
        extract(shortcode_atts(array(
            'price' => '',
            'currency' => '',
            'language' => '',
        ), $attributes));
        $getPrice = is_cart() ? WC()->cart->get_total( null ) : $this->getDisplayedProductPrice();
        $dataPrice = !empty($price) ? $price : $getPrice;
        $dataCurrency = !empty($currency) ? $currency : get_woocommerce_currency();
        $dataLanguage = !empty($language) ? $language : substr(get_locale(), 0, 2);


		$tamaraExcludedProductItems = TamaraCheckout::getInstance()->getExcludedProductIds() ?? null;
		$tamaraExcludedProductCategories = TamaraCheckout::getInstance()->getExcludedProductCategoryIds() ?? null;
		$cartItemIds = TamaraCheckout::getInstance()->getAllProductIdsInCart();
		$cartItemCategoryIds = TamaraCheckout::getInstance()->getAllProductCategoryIdsInCart();
		$tamaraExcludedProductItemsInCart = (count(array_intersect(
			$cartItemIds, $tamaraExcludedProductItems))) ? true : false;
		$tamaraExcludedProductCategoriesInCart = (count(array_intersect(
			$cartItemCategoryIds, $tamaraExcludedProductCategories))) ? true : false;

        if ($this->isCartWidgetPopupDisabled() ||
            ($tamaraExcludedProductItemsInCart) ||
            ($tamaraExcludedProductCategoriesInCart)
		) {
            return false;
        } else {
            $itemPrice = is_array($dataPrice) ? $this->getAppropriateVariationProductPrice($dataPrice) : $dataPrice;
            return $this->getServiceView()->render('views/woocommerce/checkout/tamara-popup-widget',
                [
                    'dataPrice' => $itemPrice ?? 0,
                    'dataCurrency' => $dataCurrency,
                    'dataLanguage' => $dataLanguage ?? 'en',
                    'inlineType' => static::TAMARA_INLINE_TYPE_PRODUCT_WIDGET_INT,
                ]);
        }
    }

    /**
     * Show Tamara popup widget
     */
    public function showTamaraProductPopupWidget()
    {
        if ($this->isTamaraGatewayEnabled()) {
            echo do_shortcode('[tamara_show_popup]');
        }
    }

    /**
     * Show Tamara popup widget on Cart page
     */
    public function showTamaraCartProductPopupWidget()
    {
        if ($this->isTamaraGatewayEnabled() && !$this->isCartWidgetPopupDisabled()) {
            echo do_shortcode('[tamara_show_cart_popup]');
        }
    }

    /**
     * Get displayed product price on FE
     */
    public function getDisplayedProductPrice()
    {
        global $product;
        if ($product) {
            if ($product instanceof \WC_Product) {
                if ($product instanceof \WC_Product_Variable) {
                    return $product->get_variation_prices(true)['price'];
                } else {
                    return wc_get_price_to_display($product);
                }
            }
        }

        return null;
    }

    /**
     * Get displayed product id on FE
     */
    public function getDisplayedProductId()
    {
        global $product;
        if ($product) {
            if ($product instanceof \WC_Product) {
                return $product->get_id();
            }
        }

        return null;
    }

    /**
     * Get all category ids of displayed product on FE
     */
    public function getDisplayedProductCategoryIds()
    {
        global $product;
        if ($product) {
            if ($product instanceof \WC_Product) {
                $productId = $product->get_id();

                return wc_get_product_cat_ids($productId);
            }
        }

        return null;
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * @param $productPrice
     *
     * @return bool
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function isProductPriceValid($productPrice)
    {
        // Force pull country payment types from remote api
        $countryPaymentTypes = $this->getWCTamaraGatewayService()->getCountryPaymentTypes();
        $paymentTypes = $this->getWCTamaraGatewayService()->getPaymentTypes();

        if (!$this->isAlwaysShowWidgetPopupEnabled() && !$this->getWCTamaraGatewayService()->isSingleCheckoutEnabled()) {
            if (is_array($productPrice)) {
                foreach ($productPrice as $item => $variationPrice) {
                    if (($this->getWCTamaraGatewayService()->populateMinLimit() <= $variationPrice
                         && $this->getWCTamaraGatewayService()->populateMaxLimit() >= $variationPrice)
                        || ($this->populatePayInXsLimitAmountBasedOnProductPrice($variationPrice)['instalmentMinAmount'] <= $variationPrice
                            && $this->populatePayInXsLimitAmountBasedOnProductPrice($variationPrice)['instalmentMaxAmount'] >= $variationPrice)
                        || ($this->populatePayNextMonthMinLimit() <= $variationPrice
                            && $this->populatePayNextMonthMaxLimit() >= $variationPrice)
                    ) {
                        return true;
                        break;
                    }
                }
            } else {
                return ($this->getWCTamaraGatewayService()->populateMinLimit() <= $productPrice
                        && $this->getWCTamaraGatewayService()->populateMaxLimit() >= $productPrice)
                       || ($this->populatePayInXsLimitAmountBasedOnProductPrice($productPrice)['instalmentMinAmount'] <= $productPrice
                           && $this->populatePayInXsLimitAmountBasedOnProductPrice($productPrice)['instalmentMaxAmount'] >= $productPrice)
                       || ($this->populatePayNextMonthMinLimit() <= $productPrice
                           && $this->populatePayNextMonthMaxLimit() >= $productPrice);
            }
        } else {
            return true;
        }
    }

    /**
     * Modify which total amount should be used to display on checkout page
     *
     * @param $amount
     *
     * @return mixed
     */
    public function getTotalToCalculate($amount)
    {
        if (is_checkout_pay_page()) {
            global $wp;
            if (isset($wp->query_vars['order-pay']) && absint($wp->query_vars['order-pay']) > 0) {
                $orderId = absint($wp->query_vars['order-pay']);
                $wcOrder = wc_get_order($orderId);
                if ($wcOrder) {
                    return $wcOrder->get_total();
                }
            }
        }

        return $amount;
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Update Tamara checkout data to order meta data created via rest api
     *
     * @param \WP_REST_Response $response The response object.
     * @param \WP_Post $post Post object.
     * @param \WP_REST_Request $request Request object.
     *
     * @return mixed
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function updateTamaraCheckoutDataToOrder($response, $post, $request)
    {
        $wcOrder = wc_get_order($post);

        if (!empty($wcOrder) && $this->isTamaraGateway($wcOrder->get_payment_method())) {
            $wcOrderId = $wcOrder->get_id();
            $hasTamaraCheckoutUrl = !!get_post_meta($wcOrderId, 'tamara_checkout_url', true);
            $hasTamaraCheckoutSessionId = !!get_post_meta($wcOrderId, 'tamara_checkout_session_id', true);
            if (!$hasTamaraCheckoutUrl && !$hasTamaraCheckoutSessionId) {
                $tamaraCheckoutResponse = $this->getWCTamaraGatewayService()->tamaraCheckoutSession($wcOrderId);
                if ($tamaraCheckoutResponse) {
                    $response_data = $response->get_data();
                    $metaData = [
                        [
                            'key' => 'tamara_checkout_session_id',
                            'value' => $tamaraCheckoutResponse['tamaraCheckoutSessionId'] ?: null,
                        ],
                        [
                            'key' => 'tamara_checkout_url',
                            'value' => $tamaraCheckoutResponse['tamaraCheckoutUrl'] ?: null,
                        ],
                    ];
                    $response_data['meta_data'] = $response_data['meta_data'] + $metaData;
                    $response->set_data($response_data);
                }
            }
        }

        return $response;
    }

    /**
     * Check a request a Rest API request or not
     * @return bool
     */
    public static function isRestRequest()
    {
        $requestUri = !empty($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : null;

        return $requestUri && strpos($requestUri, 'wp-json') !== false;
    }

    /**
     * Set Rest Api Request to $restApiRequest variable
     *
     * @param $restApiRequest
     */
    public function setRestApiRequest($restApiRequest)
    {
        $this->restApiRequest = $restApiRequest;
    }

    /**
     * Return the Rest Api Request
     *
     * @return \WP_REST_Request
     */
    public function getRestApiRequest()
    {
        return $this->restApiRequest;
    }

    /**
     * Redirect Pay By Instalments settings page to Pay By Later settings page
     */
    public function updatePayByInstalmentSettingUrl()
    {
        if (is_admin() && isset($_GET['page'], $_GET['tab'], $_GET['section'])
            && ('wc-settings' === $_GET['page'])
            && ('checkout' === $_GET['tab'])
            && (in_array($_GET['section'], $this->getPayInXIds()))) {
            wp_redirect(admin_url('admin.php?page=wc-settings&tab=checkout&section='.strtolower(static::TAMARA_GATEWAY_ID)));
        }
    }

    /**
     * @param $fields
     * @param $country
     *
     * @return mixed
     */
    public function forceRequireBillingPhone($fields, $country)
    {
        if (is_wc_endpoint_url('edit-address') || !$this->isForceBillingPhoneEnabled() || !empty($fields['billing_phone'])) {
            return $fields;
        } elseif ($this->isForceBillingPhoneEnabled() && empty($fields['billing_phone'])) {
            $fields['billing_phone'] = [
                'label' => __('Phone', 'tamara-checkout'),
                'required' => true,
            ];

            return $fields;
        }

        return $fields;
    }

    /**
     * Fire an ajax request without waiting for response
     */
    public function addCronJobTriggerScript()
    {
        $ajaxCronjobUrl = esc_attr(add_query_arg([
            'action' => 'tamara_perform_cron',
        ], admin_url('admin-ajax.php')));

		$sectionSlug = isset($_GET['section']) ? esc_attr(sanitize_text_field(wp_unslash($_GET['section']))) : '';
        echo '<script type="text/javascript">
        var data = {
            \'action\': \'tamara_perform_cron\'
        };
		var sectionSlug = "' . esc_js($sectionSlug) . '";
		var randomNumber = Math.floor(Math.random() * 20) + 1;
		if (randomNumber === 1 || (typeof pagenow !== \'undefined\' && pagenow === \'woocommerce_page_wc-settings\' && sectionSlug === \'tamara-gateway\')) {
			fetch("' . esc_js($ajaxCronjobUrl) . '", {
				credentials: \'same-origin\',
				method: \'GET\',
				headers: {
					\'Content-Type\': \'application/json\',
				},
			});
		}
    </script>';
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * @return false|string
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function performCron()
    {
        if (current_user_can('publish_posts')) {
            $this->forceAuthoriseTamaraOrder();
            $this->forceCaptureTamaraOrder();

            return json_encode(true);
        }

        return json_encode(false);

    }

    /**
     * @param string $url
     *
     * @return string
     */
    public function removeTrailingSlashes($url)
    {
        return rtrim(trim($url), '/');
    }

    /**
     * Get the array of Pay In X Ids
     *
     * @return array
     */
    public function getPayInXIds()
    {
        return [
            static::TAMARA_GATEWAY_CHECKOUT_ID,
            static::TAMARA_GATEWAY_PAY_IN_2,
            static::TAMARA_GATEWAY_PAY_IN_3,
            static::TAMARA_GATEWAY_PAY_IN_4,
            static::TAMARA_GATEWAY_PAY_IN_5,
            static::TAMARA_GATEWAY_PAY_IN_6,
            static::TAMARA_GATEWAY_PAY_IN_7,
            static::TAMARA_GATEWAY_PAY_IN_8,
            static::TAMARA_GATEWAY_PAY_IN_9,
            static::TAMARA_GATEWAY_PAY_IN_10,
            static::TAMARA_GATEWAY_PAY_IN_11,
            static::TAMARA_GATEWAY_PAY_IN_12,
        ];
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Populate the array of enabled Pay In Xs min amount
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function populateMinAmountArrayOfEnabledPayInXs()
    {
        $countryCode = $this->getWCTamaraGatewayService()->getCurrentCountryCode();
        $payInXMinAmount = [];
        for ($i = 12; $i >= 2; $i--) {
            if ($this->getWCTamaraGatewayService()->isSingleCheckoutEnabled()) {
                $payInXMaxAmount[$i] = $this->populateInstalmentPayInXMaxLimit($i, $countryCode);
            } else {
                if ($this->isPayInXEnabled($i, $countryCode)) {
                    $payInXMinAmount[$i] = $this->populateInstalmentPayInXMinLimit($i, $countryCode);
                }
            }
        }

        return $payInXMinAmount;
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Populate the array of enabled Pay In Xs max amount
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function populateMaxAmountArrayOfEnabledPayInXs()
    {
        $countryCode = $this->getWCTamaraGatewayService()->getCurrentCountryCode();
        $payInXMaxAmount = [];
        for ($i = 12; $i >= 2; $i--) {
            if ($this->getWCTamaraGatewayService()->isSingleCheckoutEnabled()) {
                $payInXMaxAmount[$i] = $this->populateInstalmentPayInXMaxLimit($i, $countryCode);
            } else {
                if ($this->isPayInXEnabled($i, $countryCode)) {
                    $payInXMaxAmount[$i] = $this->populateInstalmentPayInXMaxLimit($i, $countryCode);
                }
            }
        }

        return $payInXMaxAmount;
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Get min amount priority instalment period
     *
     * @return int | null
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function getMinAmountOfEnabledPriorityInstalment()
    {
        $minAmountArr = $this->populateMinAmountArrayOfEnabledPayInXs() ?? [];
        if (!empty($minAmountArr)) {
            $filterNullVarArr = array_filter($minAmountArr, function ($v) {
                return !is_null($v);
            });
            if (!empty($filterNullVarArr)) {
                return $minAmountArr[max(array_keys($filterNullVarArr))];
            }
        }

        return null;
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Get max amount priority instalment period
     *
     * @return int | null
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function getMaxAmountOfEnabledPriorityInstalment()
    {
        $maxAmountArr = $this->populateMaxAmountArrayOfEnabledPayInXs() ?? [];
        if (!empty($maxAmountArr)) {
            $filterNullVarArr = array_filter($maxAmountArr, function ($v) {
                return !is_null($v);
            });
            if (!empty($filterNullVarArr)) {
                return $maxAmountArr[max(array_keys($filterNullVarArr))];
            }
        }

        return null;
    }

    /** @noinspection PhpFullyQualifiedNameUsageInspection */
    /**
     * Get priority instalment period amongs enabled Pay In Xs
     *
     * @return int | null
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function getPriorityInstalmentPeriod()
    {
        $maxAmountArr = $this->populateMaxAmountArrayOfEnabledPayInXs() ?? [];
        if (!empty($maxAmountArr)) {
            $filterNullVarArr = array_filter($maxAmountArr, function ($v) {
                return !is_null($v);
            });

            return max(array_keys($filterNullVarArr));
        }

        return null;
    }

    /**
     * Check if current screen is Tamara Admin Settings page
     *
     * @return bool
     */
    public function isTamaraAdminSettingsScreen()
    {
        return (is_admin() && isset($_GET['page'], $_GET['tab'], $_GET['section'])
                && ('wc-settings' === $_GET['page'])
                && ('checkout' === $_GET['tab'])
                && (static::TAMARA_GATEWAY_ID === $_GET['section']));
    }

    /**
     * Return the array of Tamara Gateway Ids
     *
     * @return array
     */
    public function getAllTamaraGatewayIds()
    {
        return [
            static::TAMARA_GATEWAY_ID,
            static::TAMARA_GATEWAY_PAY_NOW,
            static::TAMARA_GATEWAY_PAY_NEXT_MONTH,
            static::TAMARA_GATEWAY_PAY_BY_INSTALMENTS_ID,
            static::TAMARA_GATEWAY_PAY_IN_2,
            static::TAMARA_GATEWAY_PAY_IN_3,
            static::TAMARA_GATEWAY_PAY_IN_4,
            static::TAMARA_GATEWAY_PAY_IN_5,
            static::TAMARA_GATEWAY_PAY_IN_6,
            static::TAMARA_GATEWAY_PAY_IN_7,
            static::TAMARA_GATEWAY_PAY_IN_8,
            static::TAMARA_GATEWAY_PAY_IN_9,
            static::TAMARA_GATEWAY_PAY_IN_10,
            static::TAMARA_GATEWAY_PAY_IN_11,
            static::TAMARA_GATEWAY_PAY_IN_12,
            static::TAMARA_GATEWAY_CHECKOUT_ID,
        ];
    }

    /**
     * Check if a payment method is Tamara
     *
     * @param $paymentMethodId
     *
     * @return bool
     */
    public function isTamaraGateway($paymentMethodId)
    {
        return !!in_array($paymentMethodId, $this->getAllTamaraGatewayIds());
    }

    /**
     * Get all product ids of items in cart, including parent and child ids.
     *
     * @return array
     */
    public function getAllProductIdsInCart()
    {
		$productIds = [];
		if (empty(WC()->cart)) {
			return $productIds;
		}

        $allCartItems = WC()->cart->get_cart();
        foreach ($allCartItems as $item => $values) {
            $itemId = $values['data']->get_id() ?? null;
            $productIds[] = $itemId;
            $product = wc_get_product($itemId);
            // Check if a product is a variation add add its parent id to the list.
            if ($product instanceof \WC_Product_Variation) {
                $productParentId = $product->get_parent_id() ?? null;
                if (!in_array($productParentId, $productIds)) {
                    $productIds[] = $productParentId;
                }
            }
        }

        return $productIds;
    }

    /**
     * Get all category ids of items in cart, including ancestors and subcategories.
     *
     * @return array
     */
    public function getAllProductCategoryIdsInCart()
    {
        $allCartItems = WC()->cart->get_cart();
        $allProductCategoryIds = [];

        foreach ($allCartItems as $item => $values) {
            $productId = $values['data']->get_id() ?? null;
            $allProductCategoryIds = array_merge($allProductCategoryIds, wc_get_product_cat_ids($productId));
        }

        return $allProductCategoryIds;
    }

    /**
     * Get the array of Tamara excluded product ids
     *
     * @return array
     */
    public function getExcludedProductIds()
    {
        $tamaraExcludedProductsOption = $this->getWCTamaraGatewayOptions()['excluded_products'] ?? '';

        return array_map('trim', explode(',',
            $tamaraExcludedProductsOption));
    }

    /**
     * Get the array of Tamara excluded product category ids
     *
     * @return array
     */
    public function getExcludedProductCategoryIds()
    {
        $tamaraExcludedProductCategoriesOption = $this->getWCTamaraGatewayOptions()['excluded_product_categories'] ?? '';

        return array_map('trim', explode(',',
            $tamaraExcludedProductCategoriesOption));
    }

    /**
     * Check if a product is excluded from using Tamara
     *
     * @param int $productId
     *
     * @return bool
     */
    public function isExcludedProduct($productId)
    {
        return !!(in_array($productId, $this->getExcludedProductIds()));
    }

    /**
     * Check if there's any product category id is excluded from using Tamara
     *
     * @param array $productCategoryIds
     *
     * @return bool
     */
    public function isExcludedProductCategory($productCategoryIds)
    {
        return !!(count(array_intersect($productCategoryIds, $this->getExcludedProductCategoryIds())));
    }

    /**
     * Get the base url of plugin
     *
     * @return string
     */
    public function getBaseUrl()
    {
        return $this->baseUrl;
    }

    /**
     * Get appropriate instalment plan according to current product variation price
     * and return the value through ajax call
     */
    public function getInstalmentPlanAccordingToProductVariation()
    {
        $variationPrice = isset($_POST['variationPrice']) ? sanitize_text_field(wp_unslash($_POST['variationPrice'])) : '';
        if (!empty($variationPrice) && !$this->isWidgetPopupDisabled()) {
            $currency = get_woocommerce_currency();
            // Todo: Handle and re-generate if PDP is not initialized when there is no plan for the smallest variation price
            $PDPWidgetData = $this->populatePDPWidgetBasedOnPrice($variationPrice, $currency) ?? [];
            if (!empty($PDPWidgetData['paymentType'])) {
                wp_send_json([
                    'message' => 'success',
                    'data' => $PDPWidgetData,
                ]);
            }
        }

        wp_send_json(
            [
                'message' => 'No payment type found for this price',
            ]
        );
    }

    /**
     * Update Tamara Checkout Params on updated_checkout event
     * and return the value through ajax call
     */
    public function updateTamaraCheckoutParams()
    {
        $storeCurrency = get_woocommerce_currency();
        $countryCode = $this->getWCTamaraGatewayService()->getCurrentCountryCode();

        wp_send_json(
            [
                'message' => 'success',
                'country' => $countryCode,
                'currency' => $storeCurrency,
            ]
        );
    }

    /**
     * Return the first value in variation product price array that meets the smallest instalment plan
     *
     * @param array $variationPriceArr
     *
     * @return mixed
     */
    public function getAppropriateVariationProductPrice($variationPriceArr)
    {
		return array_values($variationPriceArr)[0] ?? null;
        foreach ($variationPriceArr as $item => $variationPrice) {
            if (($this->getWCTamaraGatewayService()->populateMinLimit() <= $variationPrice
                 && $this->getWCTamaraGatewayService()->populateMaxLimit() >= $variationPrice)
                || ($this->populatePayInXsLimitAmountBasedOnProductPrice($variationPrice)['instalmentMinAmount'] <= $variationPrice
                    && $this->populatePayInXsLimitAmountBasedOnProductPrice($variationPrice)['instalmentMaxAmount'] >= $variationPrice)) {
                return $variationPrice;
                break;
            } elseif ($this->isAlwaysShowWidgetPopupEnabled() && !$this->isWidgetPopupDisabled()) {
                return $variationPrice;
                break;
            }
        }

        return null;
    }

    /**
     * Override Wc Clear Cart function and keep cart for orders with cancelled/failed payments from Tamara
     */
    public function overrideWcClearCart()
    {
		if (!empty(WC()->session->order_awaiting_payment)) {
            $order = wc_get_order(WC()->session->order_awaiting_payment);
            if ($order && $order->get_id() > 0) {
                // If the order has not failed, or is not pending, the order must have gone through.
                if ($this->isTamaraGateway($order->get_payment_method())) {

					if ($order->has_status(array('tamara-p-canceled', 'tamara-p-failed'))) {
						remove_action('template_redirect', 'wc_clear_cart_after_payment');
						remove_action('template_redirect', 'wc_clear_cart_after_payment', 20);
					}

                }
            }
        }
    }

    /**
     * Cancel a pending order and add Tamara payment cancelled/failed notice.
     */
    public function cancelOrder()
    {
        if (
            isset($_GET['cancel_order']) &&
            isset($_GET['order']) &&
            isset($_GET['order_id']) &&
            (isset($_GET['_wpnonce']) && wp_verify_nonce(sanitize_text_field(wp_unslash($_GET['_wpnonce'])), 'woocommerce-cancel_order'))
        ) {
            wc_nocache_headers();
            $order_key = wp_unslash($_GET['order']); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
            $order_id = absint($_GET['order_id']);
            $order = wc_get_order($order_id);
            $paymentMethod = $order->get_payment_method();
            $user_can_cancel = current_user_can('cancel_order', $order_id);
            $order_can_cancel = $order->has_status(apply_filters('woocommerce_valid_order_statuses_for_cancel', array('pending', 'failed'), $order));
            $redirect = isset($_GET['redirect']) ? wp_unslash($_GET['redirect']) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized

            if ($user_can_cancel && !$order_can_cancel && $this->isTamaraGateway($paymentMethod)) {
                wc_clear_notices();
                wc_add_notice(__('Your payment via Tamara has failed, please try again with a different payment method.', 'tamara-checkout'), 'error');
            }

            if ($redirect) {
                wp_safe_redirect($redirect);
                exit;
            }
        }
    }

    /**
     * Update phone number on every ajax calls on checkout
     *
     * @param $postedData
     *
     * @return void
     */
    public function getUpdatedPhoneNumberOnCheckout($postedData)
    {
        global $woocommerce;

        // Parsing posted data on checkout
        $post = array();
        $vars = explode('&', $postedData);
        foreach ($vars as $k => $value) {
            $v = explode('=', urldecode($value));
            $post[$v[0]] = $v[1];
        }

        // Update phone number get from posted data
        $this->customerPhoneNumber = $post['billing_phone'];
    }

    /**
     * Return customer phone number
     *
     * @return string
     */
    public function getCustomerPhoneNumber()
    {
        return $this->customerPhoneNumber;
    }

    /**
     * Update WC Order Payment method according to Tamara order
     *
     * @param $wcOrderId
     * @param $wcOrder
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function updateWcOrderPaymentMethodAccordingToTamaraOrder($wcOrderId, $wcOrder)
    {
        $tamaraOrder = $this->getTamaraOrderByWcOrderId($wcOrderId);
        $paymentType = $tamaraOrder->getPaymentType();
        update_post_meta($wcOrderId, 'tamara_payment_type', $paymentType);

        if ($paymentType === $this->getWCTamaraGatewayService()->getPaymentTypeMapping()[static::TAMARA_GATEWAY_ID]) {
            update_post_meta($wcOrderId, 'payment_method', static::TAMARA_GATEWAY_ID);
            delete_post_meta($wcOrderId, 'tamara_payment_type_instalment');
            $wcOrder->set_payment_method(static::TAMARA_GATEWAY_ID);
            $wcOrder->set_payment_method_title($this->getWCTamaraGatewayService()::TAMARA_GATEWAY_DEFAULT_TITLE);
            $wcOrder->save();
        } elseif ($paymentType === WCTamaraGateway::PAYMENT_TYPE_PAY_NEXT_MONTH) {
            update_post_meta($wcOrderId, 'payment_method', static::TAMARA_GATEWAY_ID);
            delete_post_meta($wcOrderId, 'tamara_payment_type_instalment');
            $wcOrder->set_payment_method(static::TAMARA_GATEWAY_ID);
            $wcOrder->set_payment_method_title($this->getWCTamaraGatewayService()::TAMARA_GATEWAY_PAY_NEXT_MONTH_DEFAULT_TITLE);
            $wcOrder->save();
        }  elseif ($paymentType === WCTamaraGateway::PAYMENT_TYPE_PAY_NOW) {
            update_post_meta($wcOrderId, 'payment_method', static::TAMARA_GATEWAY_ID);
            delete_post_meta($wcOrderId, 'tamara_payment_type_instalment');
            $wcOrder->set_payment_method(static::TAMARA_GATEWAY_ID);
            $wcOrder->set_payment_method_title($this->getWCTamaraGatewayService()::TAMARA_GATEWAY_PAY_NOW_DEFAULT_TITLE);
            $wcOrder->save();
        } else {
            $instalment = $tamaraOrder->getInstalments();
            update_post_meta($wcOrderId, 'payment_method', static::TAMARA_GATEWAY_PAY_IN_X.$instalment);
            update_post_meta($wcOrderId, 'tamara_payment_type_instalment', $instalment);
            $wcOrder->set_payment_method(static::TAMARA_GATEWAY_PAY_IN_X.$instalment);
            $wcOrder->set_payment_method_title($this->getWCTamaraGatewayService()->getPayInXTitle($instalment));
            $wcOrder->save();
        }
    }

    /**
     * Add Tamara Single Checkout to existing available gateways
     *
     * @param $availableGateways
     *
     * @return array
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    protected function possiblyAddTamaraSingleCheckout($availableGateways)
    {
        $singleCheckoutService = [static::TAMARA_GATEWAY_CHECKOUT_ID => $this->getWCTamaraGatewayCheckoutService()];
        $availableGateways = $this->mergeTamaraPaymentMethodsAfterPayLaterOffset($singleCheckoutService, $availableGateways);
        $payNowService = [static::TAMARA_GATEWAY_PAY_NOW => $this->getWCTamaraGatewayPayNowService()];
        $availableGateways = $this->mergeTamaraPaymentMethodsAfterPayLaterOffset($payNowService, $availableGateways);
        unset($availableGateways[static::TAMARA_GATEWAY_ID]);
        return $availableGateways;
    }

    /**
     * Add other Tamara payment methods right after Pay Later offset on checkout
     *
     * @param $array
     * @param $availableGateways
     *
     * @return array
     */
    protected function mergeTamaraPaymentMethodsAfterPayLaterOffset($array, $availableGateways)
    {
        $tamaraPayLaterKey = static::TAMARA_GATEWAY_ID;
        $tamaraPayLaterOffset = array_search($tamaraPayLaterKey, array_keys(WC()->payment_gateways->payment_gateways()));

        return array_merge(
            array_slice($availableGateways, 0, $tamaraPayLaterOffset),
            $array,
            array_slice($availableGateways, $tamaraPayLaterOffset, null)
        );
    }

    protected function isAfterTamaraAuthorised($orderStatus)
    {
        return !!in_array($orderStatus, $this->getAfterTamaraAuthorisedStatuses());
    }

    protected function getAfterTamaraAuthorisedStatuses()
    {
        return [
            static::TAMARA_CANCELED_STATUS,
            static::TAMARA_PARTIALLY_CAPTURED_STATUS,
            static::TAMARA_FULLY_CAPTURED_STATUS,
            static::TAMARA_PARTIALLY_REFUNDED_STATUS,
            static::TAMARA_FULLY_REFUNDED_STATUS
        ];
    }

    protected function isSupportedCountry($countryCode)
    {
        $supportedCountries = ['SA', 'AE', 'KW', 'BH'];

        return !!in_array($countryCode, $supportedCountries);
    }

    /**
     * Get Tamara order status from remote
     *
     * @param $wcOrderId
     *
     * @return string
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function getTamaraOrderStatus($wcOrderId)
    {
        $tamaraOrder = $this->getTamaraOrderByWcOrderId($wcOrderId);
        if ($tamaraOrder) {
            return $tamaraOrder->getStatus() ?? null;
        }

        return null;
    }

}
