<?php

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

class PGZW_Gateway extends WC_Payment_Gateway {

	/**
	 * Characters allowed in a ZainPay transaction reference. Covers both the
	 * "WC|{order_id}|{timestamp}" form this plugin generates and the
	 * "{random}_{timestamp}" form the inline SDK substitutes.
	 */
	const REFERENCE_PATTERN = '/^[A-Za-z0-9._|-]{1,128}$/';

	/**
	 * Is test mode active?
	 *
	 * @var bool
	 */
	public $testmode;

	/**
	 * Should orders be marked as complete after payment?
	 * 
	 * @var bool
	 */
	public $autocomplete_order;

	/**
	 * ZainPay payment page type.
	 *
	 * @var string
	 */
	public $payment_page;

	/**
	 * ZainPay test API token.
	 *
	 * @var string
	 */
	public $test_api_token;

	/**
	 * ZainPay test zainbox code.
	 *
	 * @var string
	 */
	public $test_zainbox_code;
	public $live_api_token;
	public $live_zainbox_code;
	public $test_inline_key;
	public $live_inline_key;
	public $saved_cards;
	public $custom_metadata;
	public $meta_order_id;
	public $meta_name;

	public $meta_email;
	public $meta_phone;
	public $debug;

	/**
	 * Webhook secret for validating incoming webhooks
	 *
	 * @var string
	 */
	public $webhook_secret;

	/**
	 * Test mode webhook secret
	 *
	 * @var string
	 */
	public $test_webhook_secret;

	/**
	 * Live mode webhook secret
	 *
	 * @var string
	 */
	public $live_webhook_secret;

	/**
	 * API token
	 *
	 * @var string
	 */
	public $api_token;

	/**
	 * ZainBox code
	 *
	 * @var string
	 */
	public $zainbox_code;

	/**
	 * Gateway disabled message
	 *
	 * @var string
	 */
	public $msg;

	/**
	 * Constructor
	 */
	public function __construct() {
		$this->id                 = 'pgzw_zainpay';
        $this->method_title       = __( 'ZainPay', 'payment-gateway-for-zainpay-for-woocommerce' );
        /* translators: 1: ZainPay marketing site, 2: ZainPay dashboard url */
		$this->method_description = sprintf( __( 'ZainPay provides merchants with the tools and services needed to accept online payments from local and international customers using Mastercard, Visa, Verve Cards and Bank Accounts. <a href="%1$s" target="_blank">Sign up</a> for a ZainPay account, and <a href="%2$s" target="_blank">get your API credentials</a>.', 'payment-gateway-for-zainpay-for-woocommerce' ), 'https://zainpay.ng/signup', 'https://zainpay.ng/merchant/dashboard/settings#Live-API-Keys' );
		$this->icon               = PGZW_URL . '/assets/images/zainpay.png';
        
        $this->payment_page = $this->get_option( 'payment_page' );
        $this->has_fields   = false; 

		$this->supports = array(
			'products',
			'refunds',
			'tokenization',
		);

		// Load the form fields
		$this->init_form_fields();

		// Load the settings
		$this->init_settings();

		// Get setting values
		$this->title              = $this->get_option( 'title' );
		$this->description        = $this->get_option( 'description' );
		$this->enabled            = $this->get_option( 'enabled' );
		$this->testmode           = $this->get_option( 'testmode' ) === 'yes' ? true : false;
		$this->autocomplete_order = $this->get_option( 'autocomplete_order' ) === 'yes' ? true : false;

		$this->test_api_token    = $this->get_option( 'test_api_token' );
		$this->test_zainbox_code = $this->get_option( 'test_zainbox_code' );

		$this->live_api_token    = $this->get_option( 'live_api_token' );
		$this->live_zainbox_code = $this->get_option( 'live_zainbox_code' );

		// Inline JS keys for frontend SDK
		$this->test_inline_key   = $this->get_option( 'test_inline_key' );
		$this->live_inline_key   = $this->get_option( 'live_inline_key' );

		$this->saved_cards = $this->get_option( 'saved_cards' ) === 'yes' ? true : false;

		$this->custom_metadata = $this->get_option( 'custom_metadata' ) === 'yes' ? true : false;

		$this->meta_order_id = $this->get_option( 'meta_order_id' ) === 'yes' ? true : false;
		$this->meta_name     = $this->get_option( 'meta_name' ) === 'yes' ? true : false;
		$this->meta_email    = $this->get_option( 'meta_email' ) === 'yes' ? true : false;
		$this->meta_phone    = $this->get_option( 'meta_phone' ) === 'yes' ? true : false;

		// Debug toggle
		$this->debug = $this->get_option( 'debug', 'no' ) === 'yes';

		// Webhook secrets (split test/live) with legacy fallback
		$this->test_webhook_secret = $this->get_option( 'test_webhook_secret', '' );
		$this->live_webhook_secret = $this->get_option( 'live_webhook_secret', '' );
		$legacy_webhook_secret     = $this->get_option( 'webhook_secret', '' );
		if ( empty( $this->test_webhook_secret ) && empty( $this->live_webhook_secret ) && ! empty( $legacy_webhook_secret ) ) {
			if ( $this->testmode ) {
				$this->test_webhook_secret = $legacy_webhook_secret;
			} else {
				$this->live_webhook_secret = $legacy_webhook_secret;
			}
		}
		$this->webhook_secret = $this->testmode ? $this->test_webhook_secret : $this->live_webhook_secret;

		$this->api_token    = $this->testmode ? $this->test_api_token : $this->live_api_token;
		$this->zainbox_code = $this->testmode ? $this->test_zainbox_code : $this->live_zainbox_code;

		// Hooks
		add_action( 'wp_enqueue_scripts', array( $this, 'payment_scripts' ) );
		add_action( 'admin_enqueue_scripts', array( $this, 'admin_scripts' ) );

		add_action( 'admin_notices', array( $this, 'admin_notices' ) );
		add_action(
			'woocommerce_update_options_payment_gateways_' . $this->id,
			array(
				$this,
				'process_admin_options',
			)
		);

		add_action( 'woocommerce_receipt_' . $this->id, array( $this, 'receipt_page' ) );

		// Payment listener/API hook.
		add_action( 'woocommerce_api_pgzw_zainpay', array( $this, 'verify_zainpay_transaction' ) );

		// Webhook listener/API hook.
		add_action( 'woocommerce_api_pgzw_zainpay_webhook', array( $this, 'process_webhook' ) );

		// Check if the gateway can be used.
		if ( ! $this->is_valid_for_use() ) {
			$this->enabled = false;
		}

	}

	/**
	 * Check if this gateway is enabled and available in the user's country.
	 */
	public function is_valid_for_use() {

		$supported_currencies = $this->get_supported_currencies();

		if ( ! in_array( get_woocommerce_currency(), $supported_currencies ) ) {

            /* translators: %s: admin settings url */
			$this->msg = sprintf( __( 'ZainPay does not support your store currency. Kindly set it to a supported currency <a href="%s">here</a>', 'payment-gateway-for-zainpay-for-woocommerce' ), admin_url( 'admin.php?page=wc-settings&tab=general' ) );

			return false;

		}

		return true;

	}

	/**
	 * Get supported currencies for ZainPay.
	 */
	public function get_supported_currencies() {
		$currencies = array(
			'NGN',
			'USD',
			'GBP',
			'EUR',
			'ZAR',
			'GHS',
			'KES',
			'UGX',
		);

		return apply_filters( 'pgzw_supported_currencies', $currencies );
	}

	/**
	 * Check if the current currency is supported.
	 */
	public function is_currency_supported( $currency = null ) {
		if ( null === $currency ) {
			$currency = get_woocommerce_currency();
		}

		return in_array( $currency, $this->get_supported_currencies() );
	}

	public function get_minimum_amount( $currency = null ) {
		if ( null === $currency ) {
			$currency = get_woocommerce_currency();
		}

		$minimum_amounts = array(
			'NGN' => 100,
			'USD' => 1,
			'GBP' => 1,
			'EUR' => 1,
			'ZAR' => 10,
			'GHS' => 5,
			'KES' => 100,
			'UGX' => 1000,
		);

		return isset( $minimum_amounts[ $currency ] ) ? $minimum_amounts[ $currency ] : 1;
	}

	/**
	 * Display ZainPay payment icon.
	 */
	public function get_icon() {

		$icon = '<img src="' . esc_url( PGZW_URL . '/assets/images/zainpay-full.png' ) . '" alt="' . esc_attr__( 'ZainPay Payment Options', 'payment-gateway-for-zainpay-for-woocommerce' ) . '" style="height: 50px;" />';

		return apply_filters( 'pgzw_woocommerce_gateway_icon', $icon, $this->id );

	}

	/**
	 * Check if ZainPay merchant details is filled.
	 */
	public function admin_notices() {

		if ( wp_doing_ajax() || ! is_admin() ) {
			return;
		}

		if ( $this->enabled == 'no' ) {
			return;
		}

		$screen = get_current_screen();
		if ( ! $screen || ! in_array( $screen->id, array( 'woocommerce_page_wc-settings', 'plugins' ) ) ) {
			return;
		}

		// Check required fields.
		if ( ! ( $this->api_token && $this->zainbox_code ) ) {
            /* translators: %s: admin settings url */
			echo '<div class="error"><p>' . wp_kses_post( sprintf( __( 'Please enter your ZainPay API credentials <a href="%s">here</a> to be able to use the Payment Gateway for ZainPay for WooCommerce plugin.', 'payment-gateway-for-zainpay-for-woocommerce' ), esc_url( admin_url( 'admin.php?page=wc-settings&tab=checkout&section=pgzw_zainpay' ) ) ) ) . '</p></div>';
			return;
		}

		// If inline mode is selected, ensure inline JS key is provided
		if ( 'inline' === $this->payment_page ) {
			$inline_key = $this->testmode ? $this->test_inline_key : $this->live_inline_key;
			if ( empty( $inline_key ) ) {
                /* translators: %s: admin settings url */
				echo '<div class="error"><p>' . wp_kses_post( sprintf( __( 'Inline payment is enabled but your Inline JS key is missing. Please enter it <a href="%s">here</a>.', 'payment-gateway-for-zainpay-for-woocommerce' ), esc_url( admin_url( 'admin.php?page=wc-settings&tab=checkout&section=pgzw_zainpay' ) ) ) ) . '</p></div>';
				return;
			}
		}


	}

	/**
	 * Check if this gateway is enabled.
	 */
	public function is_available() {

		if ( $this->enabled == "yes" ) {

			if ( ! ( $this->api_token && $this->zainbox_code ) ) {
				return false;
			}

			// If inline payment page is selected, ensure inline JS key is configured
			if ( 'inline' === $this->payment_page ) {
				$inline_key = $this->testmode ? $this->test_inline_key : $this->live_inline_key;
				if ( empty( $inline_key ) ) {
					return false;
				}
			}

			return true;

		}

		return false;

	}

	/**
	 * Initialise Gateway Settings Form Fields.
	 */
	public function init_form_fields() {

		$form_fields = array(
			'enabled'                => array(
				'title'       => __( 'Enable/Disable', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'label'       => __( 'Enable ZainPay', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'type'        => 'checkbox',
				'description' => __( 'Enable ZainPay as a payment option on the checkout page.', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'default'     => 'no',
				'desc_tip'    => true,
			),
			'title'                  => array(
				'title'       => __( 'Title', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'type'        => 'text',
				'description' => __( 'This controls the payment method title which the user sees during checkout.', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'default'     => __( 'Debit/Credit Cards', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'desc_tip'    => true,
			),
			'description'            => array(
				'title'       => __( 'Description', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'type'        => 'textarea',
				'description' => __( 'This controls the payment method description which the user sees during checkout.', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'default'     => __( 'Make payment using your debit and credit cards', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'desc_tip'    => true,
			),
			'testmode'               => array(
				'title'       => __( 'Test mode', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'label'       => __( 'Enable Test Mode', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'type'        => 'checkbox',
				'description' => __( 'Test mode enables you to test payments before going live. <br />Once the LIVE MODE is enabled on your ZainPay account uncheck this.', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'default'     => 'yes',
				'desc_tip'    => true,
			),
			'payment_page'           => array(
				'title'       => __( 'Payment Option', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'type'        => 'select',
				'description' => __( 'Popup shows the payment popup on the page while Redirect will redirect the customer to ZainPay to make payment.', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'default'     => '',
				'desc_tip'    => false,
				'options'     => array(
					''          => __( 'Select One', 'payment-gateway-for-zainpay-for-woocommerce' ),
					'inline'    => __( 'Popup', 'payment-gateway-for-zainpay-for-woocommerce' ),
					'redirect'  => __( 'Redirect', 'payment-gateway-for-zainpay-for-woocommerce' ),
				),
			),
			'callback_url'            => array(
				'title'       => __( 'Callback URL', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'type'        => 'text',
				'description' => __( 'Copy and paste this URL in your Zainbox callback URL field', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'default'     => WC()->api_request_url( 'pgzw_zainpay' ),
				'custom_attributes' => array(
					'readonly' => 'readonly',
				),
			),
			'test_webhook_secret'          => array(
				'title'       => __( 'Test Secret Key', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'type'        => 'password',
				'description' => __( 'Secret used to validate incoming ZainPay callbacks in test mode. Obtain from ZainPay dashboard.', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'default'     => '',
				'class'       => 'pgzw-test-field',
			),
			'live_webhook_secret'          => array(
				'title'       => __( 'Live Secret Key', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'type'        => 'password',
				'description' => __( 'Secret used to validate incoming ZainPay callbacks in live mode. Obtain from ZainPay dashboard.', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'default'     => '',
				'class'       => 'pgzw-live-field',
			),
			'test_api_token'         => array(
				'title'       => __( 'Test Public Key', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'type'        => 'password',
	            /* translators: %s: ZainPay dashboard URL */
			'description' => sprintf( __( 'Enter your Test Public Key here. <a href="%s" target="_blank">Get your API key from ZainPay dashboard</a>.', 'payment-gateway-for-zainpay-for-woocommerce' ), 'https://zainpay.ng/merchant/dashboard/settings#Test-API-Keys' ),
				'default'     => '',
				'class'       => 'pgzw-test-field',
			),
			'test_inline_key'         => array(
				'title'       => __( 'Test Inline JS Key', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'type'        => 'password',
	            /* translators: %s: ZainPay dashboard URL */
			'description' => sprintf( __( 'Enter your Test Inline JS Key here. <a href="%s" target="_blank">Get your Inline JS key from ZainPay dashboard</a>.', 'payment-gateway-for-zainpay-for-woocommerce' ), 'https://zainpay.ng/merchant/dashboard/settings#Test-API-Keys' ),
				'default'     => '',
				'class'       => 'pgzw-test-field',
			),
			'test_zainbox_code'      => array(
				'title'       => __( 'Test ZainBox Code', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'type'        => 'text',
	            /* translators: %s: ZainPay dashboard URL */
			'description' => sprintf( __( 'Enter your Test ZainBox Code here. <a href="%s" target="_blank">Get your ZainBox code from ZainPay dashboard</a>.', 'payment-gateway-for-zainpay-for-woocommerce' ), 'https://zainpay.ng/merchant/dashboard/zainboxes' ),
				'default'     => '',
				'class'       => 'pgzw-test-field',
			),
			'live_api_token'         => array(
				'title'       => __( 'Live Public Key', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'type'        => 'password',
	            /* translators: %s: ZainPay dashboard URL */
			'description' => sprintf( __( 'Enter your Live Public Key here. <a href="%s" target="_blank">Get your API keys from ZainPay dashboard</a>.', 'payment-gateway-for-zainpay-for-woocommerce' ), 'https://zainpay.ng/merchant/dashboard/settings#Live-API-Keys' ),
				'default'     => '',
				'class'       => 'pgzw-live-field',
			),
			'live_inline_key'         => array(
				'title'       => __( 'Live Inline JS Key', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'type'        => 'password',
	            /* translators: %s: ZainPay dashboard URL */
			'description' => sprintf( __( 'Enter your Live Inline JS Key here. <a href="%s" target="_blank">Get your Inline JS key from ZainPay dashboard</a>.', 'payment-gateway-for-zainpay-for-woocommerce' ), 'https://zainpay.ng/merchant/dashboard/settings#Test-API-Keys' ),
				'default'     => '',
				'class'       => 'pgzw-live-field',
			),
			'live_zainbox_code'      => array(
				'title'       => __( 'Live ZainBox Code', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'type'        => 'text',
	            /* translators: %s: ZainPay dashboard URL */
			'description' => sprintf( __( 'Enter your Live ZainBox Code here. <a href="%s" target="_blank">Get your ZainBox code from ZainPay dashboard</a>.', 'payment-gateway-for-zainpay-for-woocommerce' ), 'https://zainpay.ng/merchant/dashboard/zainboxes' ),
				'default'     => '',
				'class'       => 'pgzw-live-field',
			),
			// 'webhook_url'            => array(
			// 	'title'       => __( 'Webhook URL', 'payment-gateway-for-zainpay-for-woocommerce' ),
			// 	'type'        => 'text',
			// 	'description' => sprintf( __( 'Copy this URL to your ZainPay webhook settings: %s', 'payment-gateway-for-zainpay-for-woocommerce' ), '<br><code>' . WC()->api_request_url( 'pgzw_webhook' ) . '</code>' ),
			// 	'default'     => WC()->api_request_url( 'pgzw_webhook' ),
			// 	'custom_attributes' => array(
			// 		'readonly' => 'readonly',
			// 	),
			// ),
			'autocomplete_order'     => array(
				'title'       => __( 'Autocomplete Order After Payment', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'label'       => __( 'Autocomplete Order', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'type'        => 'checkbox',
				'class'       => 'pgzw-autocomplete-order',
				'description' => __( 'If enabled, the order will be marked as complete after successful payment', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'default'     => 'no',
				'desc_tip'    => true,
			),
			'saved_cards'            => array(
				'title'       => __( 'Saved Cards', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'label'       => __( 'Enable Payment via Saved Cards', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'type'        => 'checkbox',
				'description' => __( 'If enabled, users will be able to pay with a saved card during checkout. Card details are saved on ZainPay servers, not on your store.<br>Note that you need to have a valid SSL certificate installed.', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'default'     => 'no',
				'desc_tip'    => true,
			),
			'debug'                  => array(
				'title'       => __( 'Debug mode', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'label'       => __( 'Enable debug logging (do not enable on production sites)', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'type'        => 'checkbox',
				'description' => __( 'When enabled, the plugin will log diagnostic information to WooCommerce logs. Disable before submitting to the WordPress repository.', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'default'     => 'no',
				'desc_tip'    => true,
			),
			'custom_metadata'        => array(
				'title'       => __( 'Custom Metadata', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'label'       => __( 'Enable Custom Metadata', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'type'        => 'checkbox',
				'class'       => 'pgzw-metadata',
				'description' => __( 'If enabled, you will be able to send more information about the order to ZainPay.', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'default'     => 'no',
				'desc_tip'    => true,
			),
			'meta_order_id'          => array(
				'title'       => __( 'Order ID', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'label'       => __( 'Send Order ID', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'type'        => 'checkbox',
				'class'       => 'pgzw-meta-order-id',
				'description' => __( 'If checked, the Order ID will be sent to ZainPay', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'default'     => 'no',
				'desc_tip'    => true,
			),
			'meta_name'              => array(
				'title'       => __( 'Customer Name', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'label'       => __( 'Send Customer Name', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'type'        => 'checkbox',
				'class'       => 'pgzw-meta-name',
				'description' => __( 'If checked, the customer full name will be sent to ZainPay', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'default'     => 'no',
				'desc_tip'    => true,
			),
			'meta_email'             => array(
				'title'       => __( 'Customer Email', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'label'       => __( 'Send Customer Email', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'type'        => 'checkbox',
				'class'       => 'pgzw-meta-email',
				'description' => __( 'If checked, the customer email address will be sent to ZainPay', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'default'     => 'no',
				'desc_tip'    => true,
			),
			'meta_phone'             => array(
				'title'       => __( 'Customer Phone', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'label'       => __( 'Send Customer Phone', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'type'        => 'checkbox',
				'class'       => 'pgzw-meta-phone',
				'description' => __( 'If checked, the customer phone will be sent to ZainPay', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'default'     => 'no',
				'desc_tip'    => true,
			),
		);

		$this->form_fields = $form_fields;

	}

	/**
	 * Process the payment and return the result.
	 *
	 * @param int $order_id Order ID.
	 * @return array
	 */
	public function process_payment( $order_id ) {

		$order = wc_get_order( $order_id );

		if ( $this->payment_page == 'redirect' ) {
			return $this->process_redirect_payment( $order );
		} else {
			return $this->process_inline_payment( $order );
		}

	}

	/**
	 * Process inline payment (popup).
	 *
	 * @param WC_Order $order Order object.
	 * @return array
	 */
	public function process_inline_payment( $order ) {

		$order_id = $order->get_id();

		$amount = $order->get_total();
		$currency = $order->get_currency();

		// Validate currency support
        if ( ! $this->is_currency_supported( $currency ) ) {
            /* translators: %s: currency code */
            wc_add_notice( sprintf( __( 'ZainPay does not support %s currency.', 'payment-gateway-for-zainpay-for-woocommerce' ), $currency ), 'error' );
            return array(
                'result'   => 'failure',
                /* translators: %s: currency code */
                'messages' => array( sprintf( __( 'ZainPay does not support %s currency.', 'payment-gateway-for-zainpay-for-woocommerce' ), $currency ) )
            );
        }

        // Validate minimum amount
        $minimum_amount = $this->get_minimum_amount( $currency );
        if ( $amount < $minimum_amount ) {
            /* translators: 1: currency symbol, 2: minimum order amount */
            wc_add_notice( sprintf( __( 'Minimum order amount is %1$s %2$s.', 'payment-gateway-for-zainpay-for-woocommerce' ), get_woocommerce_currency_symbol( $currency ), $minimum_amount ), 'error' );
            return array(
                'result'   => 'failure',
                /* translators: 1: currency symbol, 2: minimum order amount */
                'messages' => array( sprintf( __( 'Minimum order amount is %1$s %2$s.', 'payment-gateway-for-zainpay-for-woocommerce' ), get_woocommerce_currency_symbol( $currency ), $minimum_amount ) )
            );
        }

		$pgzw_params = $this->get_pgzw_params( $order );

		$order->update_meta_data( '_zainpay_txn_ref', $pgzw_params['reference'] );
		$order->save();

		// If this is the AJAX create+init flow, initialize via server and return the authorization URL
		$action = isset( $_POST['action'] ) ? sanitize_text_field( wp_unslash( $_POST['action'] ) ) : '';
		if ( wp_doing_ajax() && 'pgzw_create_order_and_init_payment' === $action ) {
			// Verify nonce
			if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'pgzw_inline_payment' ) ) {
				wp_send_json_error( array( 'message' => __( 'Security check failed', 'payment-gateway-for-zainpay-for-woocommerce' ) ) );
			}
			// Set order to pending while awaiting user action
            /* translators: %s: transaction reference */
			$order->update_status( 'pending', sprintf( __( 'ZainPay payment initialized. Transaction reference: %s', 'payment-gateway-for-zainpay-for-woocommerce' ), $pgzw_params['reference'] ) );

			// Initialize payment with ZainPay API (server-side)
			$payment_init = $this->initialize_payment( $pgzw_params );

			$redirect_url = null;
			if ( $payment_init ) {
				if ( is_string( $payment_init ) && filter_var( $payment_init, FILTER_VALIDATE_URL ) ) {
					$redirect_url = $payment_init;
				} elseif ( is_array( $payment_init ) && isset( $payment_init['authorization_url'] ) ) {
					$redirect_url = $payment_init['authorization_url'];
				}
			}

			if ( $redirect_url ) {
				wp_send_json_success( array(
					'redirect_url' => $redirect_url,
					'order_id'     => $order_id,
					'reference'    => $pgzw_params['reference'],
				) );
			} else {
                /* translators: %s: transaction reference */
				$order->update_status( 'failed', sprintf( __( 'ZainPay payment initialization failed. Reference: %s', 'payment-gateway-for-zainpay-for-woocommerce' ), $pgzw_params['reference'] ) );
				wp_send_json_error( array( 'message' => __( 'Unable to process payment. Please try again.', 'payment-gateway-for-zainpay-for-woocommerce' ) ) );
			}
		}

		return array(
			'result'   => 'success',
			'redirect' => $order->get_checkout_payment_url( true ),
		);

	}

	/**
	 * Process redirect payment.
	 */
	public function process_redirect_payment( $order ) {

		$order_id = $order->get_id();

		$amount = $order->get_total();
		$currency = $order->get_currency();

		// Log payment attempt
		$this->log( sprintf( 'Processing redirect payment for Order #%d. Amount: %s %s', $order_id, $amount, $currency ) );

		// Validate currency support
        if ( ! $this->is_currency_supported( $currency ) ) {
            $error_msg = sprintf( 'ZainPay does not support %s currency for Order #%d', $currency, $order_id );
            $this->log( $error_msg, 'error' );
            /* translators: %s: currency code */
            wc_add_notice( sprintf( __( 'ZainPay does not support %s currency.', 'payment-gateway-for-zainpay-for-woocommerce' ), $currency ), 'error' );
            return array(
                'result'   => 'failure',
                /* translators: %s: currency code */
                'messages' => array( sprintf( __( 'ZainPay does not support %s currency.', 'payment-gateway-for-zainpay-for-woocommerce' ), $currency ) )
            );
        }

        // Validate minimum amount
        $minimum_amount = $this->get_minimum_amount( $currency );
        if ( $amount < $minimum_amount ) {
            $error_msg = sprintf( 'Order #%d amount (%s %s) is below minimum (%s %s)', $order_id, $amount, $currency, $minimum_amount, $currency );
            $this->log( $error_msg, 'error' );
            /* translators: 1: currency symbol, 2: minimum order amount */
            wc_add_notice( sprintf( __( 'Minimum order amount is %1$s %2$s.', 'payment-gateway-for-zainpay-for-woocommerce' ), get_woocommerce_currency_symbol( $currency ), $minimum_amount ), 'error' );
            return array(
                'result'   => 'failure',
                /* translators: 1: currency symbol, 2: minimum order amount */
                'messages' => array( sprintf( __( 'Minimum order amount is %1$s %2$s.', 'payment-gateway-for-zainpay-for-woocommerce' ), get_woocommerce_currency_symbol( $currency ), $minimum_amount ) )
            );
        }

		$pgzw_params = $this->get_pgzw_params( $order );

		$order->update_meta_data( '_zainpay_txn_ref', $pgzw_params['reference'] );
		$order->save();

		// Log payment parameters
		$this->log( sprintf( 'ZainPay parameters for Order #%d: Reference=%s, Email=%s, Amount=%s', $order_id, $pgzw_params['reference'], $pgzw_params['email'], $pgzw_params['amount'] ) );

		// Initialize payment with ZainPay API
		$payment_init = $this->initialize_payment( $pgzw_params );

		// Handle both string URL response and array response with authorization_url
		$redirect_url = null;
		if ( $payment_init ) {
			if ( is_string( $payment_init ) && filter_var( $payment_init, FILTER_VALIDATE_URL ) ) {
				// Direct URL string response
				$redirect_url = $payment_init;
			} elseif ( is_array( $payment_init ) && isset( $payment_init['authorization_url'] ) ) {
				// Array response with authorization_url key
				$redirect_url = $payment_init['authorization_url'];
			}
		}

		if ( $redirect_url ) {
			$this->log( sprintf( 'Payment initialization successful for Order #%d. Redirect URL: %s', $order_id, $redirect_url ) );
			return array(
				'result'   => 'success',
				'redirect' => $redirect_url,
			);
		} else {
            $error_msg = sprintf( 'Payment initialization failed for Order #%d. Response: %s', $order_id, wp_json_encode( $payment_init ) );
            $this->log( $error_msg, 'error' );
            /* translators: %s: transaction reference */
            $order->update_status( 'failed', sprintf( __( 'ZainPay payment initialization failed. Reference: %s', 'payment-gateway-for-zainpay-for-woocommerce' ), $pgzw_params['reference'] ) );
            wc_add_notice( __( 'Unable to process payment. Please try again.', 'payment-gateway-for-zainpay-for-woocommerce' ), 'error' );
            return array(
                'result'   => 'failure',
                'messages' => array( __( 'Unable to process payment. Please try again.', 'payment-gateway-for-zainpay-for-woocommerce' ) )
            );
        }

	}

	/**
	 * Get the order total as a whole-number string for the ZainPay API.
	 *
	 * ZainPay rejects any amount containing a decimal point with an
	 * Invalid_amount error, so the total is rounded to the nearest major
	 * currency unit and the adjustment is recorded on the order once.
	 *
	 * @param WC_Order $order Order object.
	 * @return string
	 */
	public function get_zainpay_amount( $order ) {

		$total   = (float) $order->get_total();
		$rounded = (float) round( $total );

		if ( abs( $rounded - $total ) >= 0.005 && ! $order->get_meta( '_zainpay_amount_rounded' ) ) {
			$order->add_order_note(
				sprintf(
					/* translators: 1: formatted order total, 2: formatted amount sent to ZainPay */
					__( 'ZainPay only accepts whole-number amounts. The order total of %1$s was rounded to %2$s for this payment.', 'payment-gateway-for-zainpay-for-woocommerce' ),
					wc_price( $total, array( 'currency' => $order->get_currency() ) ),
					wc_price( $rounded, array( 'currency' => $order->get_currency(), 'decimals' => 0 ) )
				)
			);
			$order->update_meta_data( '_zainpay_amount_rounded', $rounded );
			$order->save();
		}

		return number_format( $rounded, 0, '', '' );

	}

	/**
	 * Get ZainPay payment parameters.
	 */
	public function get_pgzw_params( $order ) {

		$order_id = $order->get_id();
		$currency = $order->get_currency();

		$txnref = 'WC|' . $order_id . '|' . time();

		$callback_url  = WC()->api_request_url( 'pgzw_zainpay' );

		$pgzw_params = array(
			'amount'       => $this->get_zainpay_amount( $order ),
			'currency'     => $currency,
			'reference'    => $txnref,
			'email'        => $order->get_billing_email(),
			'phone'        => $order->get_billing_phone(),
			'callback_url' => $callback_url,
			'metadata'     => $this->get_custom_metadata( $order ),
		);

		return $pgzw_params;

	}

	/**
	 * Get custom metadata for the order.
	 */
	public function get_custom_metadata( $order ) {

		$metadata = array();

		if ( 'yes' === $this->custom_metadata ) {

			if ( 'yes' === $this->meta_order_id ) {
				$metadata['order_id'] = $order->get_id();
			}

			if ( 'yes' === $this->meta_name ) {
				$metadata['customer_name'] = $order->get_billing_first_name() . ' ' . $order->get_billing_last_name();
			}

			if ( 'yes' === $this->meta_email ) {
				$metadata['customer_email'] = $order->get_billing_email();
			}

			if ( 'yes' === $this->meta_phone ) {
				$metadata['customer_phone'] = $order->get_billing_phone();
			}

		}

		return $metadata;

	}

	/**
	 * Get ZainBox code based on test/live mode.
	 */
	public function get_zainbox_code() {
		if ( $this->testmode ) {
			return $this->test_zainbox_code;
		} else {
			return $this->live_zainbox_code;
		}
	}

	/**
	 * Log messages to WooCommerce logger.
	 *
	 * @param string $message Message to log
	 * @param string $level Log level (info, error, debug)
	 */
	public function log( $message, $level = 'info' ) {
		if ( ! $this->debug && ! in_array( $level, array( 'error', 'critical', 'alert', 'emergency' ), true ) ) {
			return;
		}
		if ( ! class_exists( 'WC_Logger' ) ) {
			return;
		}

		$logger = wc_get_logger();
		$context = array( 'source' => 'pgzw_zainpay' );

		$logger->log( $level, $message, $context );
	}

	/**
	 * Initialize payment with ZainPay API.
	 */
	public function initialize_payment( $params ) {
		try {
			$this->log( sprintf( 'Initializing payment with ZainPay API. Reference: %s, Amount: %s', $params['reference'], $params['amount'] ) );

			// Set ZainPay mode and token
			if ( $this->testmode ) {
				\Zainpay\SDK\Engine::setMode( \Zainpay\SDK\Engine::MODE_DEVELOPMENT );
				\Zainpay\SDK\Engine::setToken( $this->test_api_token );
				$this->log( sprintf( 'Using ZainPay test mode with sandbox credentials. Token: %s', empty( $this->test_api_token ) ? 'EMPTY' : 'SET' ) );
			} else {
				\Zainpay\SDK\Engine::setMode( \Zainpay\SDK\Engine::MODE_PRODUCTION );
				\Zainpay\SDK\Engine::setToken( $this->live_api_token );
				$this->log( sprintf( 'Using ZainPay live mode with production credentials. Token: %s', empty( $this->live_api_token ) ? 'EMPTY' : 'SET' ) );
			}

			$card = new \Zainpay\SDK\WordPress\Card();
			$response = $card->initializeCardPayment(
				$params['amount'],
				$params['reference'],
				$params['email'],
				$params['phone'] ?? '',
				$this->get_zainbox_code(),
				$params['callback_url']
			);

			if ( $response->hasSucceeded() ) {
				$data = $response->getData();
				$this->log( sprintf( 'ZainPay API response successful. Data: %s', wp_json_encode( is_array( $data ) ? PGZW_Utils::sanitize_array( $data ) : $data ) ) );
				
				// Handle different response formats for redirect URL
				if ( is_string( $data ) && filter_var( $data, FILTER_VALIDATE_URL ) ) {
					// Direct URL string
					return $data;
				} elseif ( is_array( $data ) && isset( $data['authorization_url'] ) ) {
					// Array with authorization_url key
					return $data['authorization_url'];
				} elseif ( is_array( $data ) && isset( $data['data'] ) && is_string( $data['data'] ) ) {
					// Nested array with data key containing URL
					return $data['data'];
				} else {
					// Return original data for backward compatibility
					return $data;
				}
			} else {
				$error_msg = $response->getDescription() ?: 'Unknown error from ZainPay API';
				$this->log( sprintf( 'ZainPay API response failed: %s', $error_msg ), 'error' );
				// Additional detailed logging for failed responses
				$response_data = $response->getData();
				$this->log( 'ZainPay Initialize Payment Failed Response Details: ' . wp_json_encode( array(
					'description' => $response->getDescription(),
					'data' => is_array( $response_data ) ? PGZW_Utils::sanitize_array( $response_data ) : $response_data,
					'reference' => $params['reference']
				) ) );
				return false;
			}

		} catch ( Exception $e ) {
			$this->log( sprintf( 'ZainPay API exception: %s', $e->getMessage() ), 'error' );
			return false;
		}

	}

	/**
	 * Verify payment transaction.
	 */
	public function verify_transaction( $reference ) {

		try {
			// Set ZainPay mode and token
			if ( $this->testmode ) {
				\Zainpay\SDK\Engine::setMode( \Zainpay\SDK\Engine::MODE_DEVELOPMENT );
				\Zainpay\SDK\Engine::setToken( $this->test_api_token );
			} else {
				\Zainpay\SDK\Engine::setMode( \Zainpay\SDK\Engine::MODE_PRODUCTION );
				\Zainpay\SDK\Engine::setToken( $this->live_api_token );
			}

			$card = new \Zainpay\SDK\WordPress\Card();
			$response = $card->verifyCardPaymentV2( $reference );

		$verification_payload = array(
			'succeeded'   => $response->hasSucceeded(),
			'description' => $response->getDescription(),
			'data'        => $response->getData(),
			'reference'   => $reference,
		);
		$verification_payload['data'] = is_array( $verification_payload['data'] ) ? PGZW_Utils::sanitize_array( $verification_payload['data'] ) : $verification_payload['data'];
		$this->log( 'ZainPay Verify API Response: ' . wp_json_encode( $verification_payload ) );

			if ( $response->hasSucceeded() ) {
				$verification_data = $response->getData();
				
				// Process verification response
				
				// Determine payment status based on available data
				$payment_status = '';
				
				// Check for explicit status field
				if ( isset( $verification_data['status'] ) ) {
					$payment_status = strtolower( $verification_data['status'] );
				} 
				// If narration contains 'approved', consider it successful
				elseif ( isset( $verification_data['narration'] ) && stripos( $verification_data['narration'], 'approved' ) !== false ) {
					$payment_status = 'success';
				}
				// If we have payment date and reference, it's likely successful
				elseif ( isset( $verification_data['paymentDate'] ) && isset( $verification_data['paymentRef'] ) ) {
					$payment_status = 'success';
				}
				
				// Add normalized status for easier checking
				$verification_data['normalized_status'] = $payment_status;
				$verification_data['is_successful'] = !empty($payment_status) && in_array( $payment_status, ['success', 'successful', 'completed', 'paid'] );
				$verification_data['is_pending'] = empty($payment_status) || in_array( $payment_status, ['pending', 'processing', 'in_progress'] );
				
				return $verification_data;
			} else {
				return false;
			}

		} catch ( Exception $e ) {
			// Handle verification error
			return false;
			}

	}

	/**
	 * Process webhook.
	 */
	public function process_webhook() {

		if ( ! isset( $_SERVER['REQUEST_METHOD'] ) || ( strtoupper( sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD'] ) ) ) != 'POST' ) ) {
			exit;
		}

		$body = file_get_contents( 'php://input' );

		if ( false === $body || '' === $body ) {
			exit;
		}

		// Validate webhook signature if secret is configured (per official docs)
		// Header: Zainpay-Signature; Algorithm: HmacSHA256(body, secret)
		if ( ! empty( $this->webhook_secret ) ) {
			$signature_header = isset( $_SERVER['HTTP_ZAINPAY_SIGNATURE'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_ZAINPAY_SIGNATURE'] ) ) : '';
			if ( ! PGZW_Utils::verify_zainpay_signature( $body, $this->webhook_secret, $signature_header ) ) {
				http_response_code( 400 );
				exit;
			}
		}

		if ( ! is_string( $body ) || '' === $body ) {
			http_response_code( 400 );
			exit;
		}

		$event = json_decode( $body, true );

		if ( ! is_array( $event ) || JSON_ERROR_NONE !== json_last_error() ) {
			http_response_code( 400 );
			exit;
		}

		$event_type = isset( $event['event'] ) ? sanitize_text_field( (string) $event['event'] ) : '';
		if ( 'charge.success' === $event_type ) {

			$data = isset( $event['data'] ) && is_array( $event['data'] ) ? $event['data'] : array();
			$reference = isset( $data['reference'] ) ? sanitize_text_field( (string) $data['reference'] ) : '';
			if ( '' === $reference || ! preg_match( self::REFERENCE_PATTERN, $reference ) ) {
				http_response_code( 400 );
				exit;
			}

			$order_id = PGZW_Utils::parse_order_id_from_reference( $reference );

			$order = wc_get_order( $order_id );

			if ( $order ) {

				$order_total    = floatval( $order->get_total() );
				$raw_amount = isset( $data['amount'] ) && is_numeric( $data['amount'] ) ? floatval( $data['amount'] ) : 0.0;
				if ( $raw_amount <= 0 ) {
					http_response_code( 400 );
					exit;
				}
				$amount_received = PGZW_Utils::normalize_amount_for_order_total( $order_total, $raw_amount ); // Net amount after fees (normalized)

				// Calculate net and fee using utility
				$calc = PGZW_Utils::compute_net_and_fee( $order_total, $amount_received );
				$fee = $calc['fee'];

				// Mark payment as complete for the full order amount regardless of fees
				if ( in_array( $order->get_status(), array( 'processing', 'completed' ) ) ) {
					// If already processing and merchant wants autocomplete, upgrade to completed
					if ( 'processing' === $order->get_status() && $this->autocomplete_order ) {
						$order->update_status( 'completed' );
					}
					exit;
				}

				$order->payment_complete( $reference );

				// Add detailed order note showing gross, fee, and net amounts
				$order_note = $this->format_payment_confirmation_note( $order, $order_total, $fee, $amount_received, $reference );
				$order->add_order_note( $order_note );

				// Save net amount and fee as order meta
				$this->save_pgzw_payment_meta( $order, $amount_received, $fee );

				// Reduce stock levels if not already done
				if ( ! $order->get_meta( '_stock_reduced', true ) ) {
					function_exists( 'wc_reduce_stock_levels' ) ? wc_reduce_stock_levels( $order_id ) : $order->reduce_order_stock();
				}

				if ( $this->autocomplete_order ) {
					$order->update_status( 'completed' );
				}

			}

		}

		wp_send_json_success( array( 'received' => true ) );

	}

	/**
	 * Format payment confirmation note
	 */
	private function format_payment_confirmation_note( $order, $order_total, $fee, $net, $reference ) {
		$currency_symbol = get_woocommerce_currency_symbol( $order->get_currency() );
		return sprintf(
			/* translators: %1$s: currency symbol, %2$s: order total, %3$s: fee, %4$s: net amount, %5$s: transaction reference */
			__( 'Payment confirmed via ZainPay. Gross %1$s%2$s, Fee %1$s%3$s, Net %1$s%4$s. (Transaction Reference: %5$s)', 'payment-gateway-for-zainpay-for-woocommerce' ),
				$currency_symbol,
				number_format( $order_total, 2 ),
				number_format( $fee, 2 ),
				number_format( $net, 2 ),
				$reference
			);
		}

		/**
		 * Save ZainPay payment meta (net amount and fee)
		 */
		private function save_pgzw_payment_meta( $order, $net, $fee ) {
			$order->update_meta_data( '_zainpay_net_amount', $net );
			$order->update_meta_data( '_zainpay_fee', $fee );
			$order->save();
		}

	private function can_enqueue_payment_scripts() {
		if ( 'no' === $this->enabled ) {
			return false;
		}

		if ( empty( $this->test_api_token ) && empty( $this->live_api_token ) ) {
			return false;
		}

		if ( ! $this->testmode && ( empty( $this->live_api_token ) || empty( $this->live_zainbox_code ) ) ) {
			return false;
		}

		if ( $this->testmode && ( empty( $this->test_api_token ) || empty( $this->test_zainbox_code ) ) ) {
			return false;
		}

		if ( 'inline' === $this->payment_page ) {
			$inline_key = $this->testmode ? $this->test_inline_key : $this->live_inline_key;
			if ( empty( $inline_key ) ) {
				return false;
			}
		}

		return true;
	}

		/**
		 * Enqueue payment scripts.
		 */
	public function payment_scripts() {
		$is_order_pay = function_exists( 'is_wc_endpoint_url' ) && is_wc_endpoint_url( 'order-pay' );

		// On blocks-based checkout pages, the blocks framework handles
		// everything. Classic JS interferes with the Store API nonce. The
		// order-pay endpoint is served from the same page but renders our own
		// receipt form, so it still needs the scripts.
		$post = get_post();
		if ( ! $is_order_pay && $post && has_block( 'woocommerce/checkout', $post ) ) {
			return;
		}

		if ( ! is_cart() && ! is_checkout() && ! $is_order_pay ) {
			return;
		}

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

		// For redirect mode, no custom JS or external SDK is needed.
		// The redirect is handled server-side via process_payment().
		if ( 'redirect' === $this->payment_page ) {
			return;
		}

		// Enqueue ZainPay inline SDK from hosted source (dev/live) — only for inline/popup mode
		$sdk_url = $this->testmode ? 'https://dev.zainpay.ng/v1/zainpay-inline.js' : 'https://api.zainpay.ng/v1/zainpay-inline.js';
		wp_enqueue_script( 'zainpay_inline_sdk', $sdk_url, array(), PGZW_VERSION, true );

		// Dev-mode switch: use non-minified when WP_DEBUG, SCRIPT_DEBUG, or plugin debug is enabled
		$dev_mode = ( defined( 'WP_DEBUG' ) && WP_DEBUG ) || ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) || $this->debug;
		$suffix   = $dev_mode ? '' : '.min';

		wp_enqueue_script( 'woocommerce_pgzw', plugins_url( 'assets/js/pgzw-zainpay' . $suffix . '.js', dirname( __DIR__ ) . '/payment-gateway-for-zainpay-for-woocommerce.php' ), array( 'jquery', 'zainpay_inline_sdk' ), PGZW_VERSION, true );
		wp_enqueue_style( 'woocommerce_pgzw', plugins_url( 'assets/css/pgzw-zainpay' . $suffix . '.css', dirname( __DIR__ ) . '/payment-gateway-for-zainpay-for-woocommerce.php' ), array(), PGZW_VERSION );

		// Determine the appropriate public key for frontend inline SDK
		$public_key = $this->testmode ? $this->test_api_token : $this->live_api_token;
		if ( 'inline' === $this->payment_page ) {
			$public_key = $this->testmode ? $this->test_inline_key : $this->live_inline_key;
		}

		$pgzw_params = array(
			'payment_page' => $this->payment_page,
			'return_url'   => $this->get_return_url(),
			'testmode'     => $this->testmode ? 'yes' : 'no',
			'poll_interval'=> 2000,
			'mode'         => $this->testmode ? 'sandbox' : 'live',
			'public_key'   => $public_key,
			'zainbox_code' => $this->get_zainbox_code(),
		);

		wp_localize_script( 'woocommerce_pgzw', 'pgzw_params', array_merge( $pgzw_params, array(
			'ajax_url' => admin_url( 'admin-ajax.php' ),
			'nonce'    => wp_create_nonce( 'pgzw_inline_payment' ),
			'status_nonce' => wp_create_nonce( 'pgzw_check_payment_status' ),
			'debug'    => $this->debug ? 'yes' : 'no',
		) ) );

	}

	/**
	 * Enqueue admin scripts.
	 */
	public function admin_scripts( $hook ) {

		if ( 'woocommerce_page_wc-settings' !== $hook ) {
			return;
		}

		$section = filter_input( INPUT_GET, 'section', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
		if ( 'pgzw_zainpay' !== $section ) {
			return;
		}

		$dev_mode = ( defined( 'WP_DEBUG' ) && WP_DEBUG ) || ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) || $this->debug;
		$suffix   = $dev_mode ? '' : '.min';
		wp_enqueue_script( 'postbox' );
		wp_enqueue_script( 'woocommerce_pgzw_admin', plugins_url( 'assets/js/pgzw-zainpay-admin' . $suffix . '.js', dirname( __DIR__ ) . '/payment-gateway-for-zainpay-for-woocommerce.php' ), array( 'jquery' ), PGZW_VERSION, true );
		wp_enqueue_style( 'woocommerce_pgzw_admin_styles', plugins_url( 'assets/css/pgzw-zainpay.css', dirname( __DIR__ ) . '/payment-gateway-for-zainpay-for-woocommerce.php' ), array(), PGZW_VERSION );

		$support_url = 'https://ibrahim.ng/contact/';
		$docs_url = 'https://ibrahim.ng/zainpay-payments-for-woocommerce-setup-guide/';
		$review_url = 'https://wordpress.org/support/plugin/payment-gateway-for-zainpay-for-woocommerce/reviews/#new-post';

		$support_content = '<p>';
		$support_content .= sprintf(
			/* translators: 1: opening anchor tag, 2: closing anchor tag */
			__( 'Whether you need help or have a new feature request, let us know. %1$sRequest Support%2$s', 'payment-gateway-for-zainpay-for-woocommerce' ),
			'<a class="pgzw-link" href="' . esc_url( $support_url ) . '" target="_blank">', '</a>'
		);
		$support_content .= '</p>';

		$support_content .= '<p>';
		$support_content .= sprintf(
			/* translators: 1: opening anchor tag, 2: closing anchor tag */
			__( 'Detailed documentation is also available on the plugin website. %1$sView Knowledge Base%2$s', 'payment-gateway-for-zainpay-for-woocommerce' ),
			'<a class="pgzw-link" href="' . esc_url( $docs_url ) . '" target="_blank">', '</a>'
		);
		$support_content .= '</p>';

		$support_content .= '<p>';
		$support_content .= sprintf(
			/* translators: 1: opening anchor tag, 2: closing anchor tag */
			__( 'If you are enjoying ZainPay and find it useful, please consider leaving a review on WordPress.org. %1$sLeave a Review%2$s', 'payment-gateway-for-zainpay-for-woocommerce' ),
			'<a class="pgzw-link" href="' . esc_url( $review_url ) . '" target="_blank">', '</a>'
		);
		$support_content .= '</p>';

		$sidebar_sections = array(
			array(
				'title'   => __( 'Need Support?', 'payment-gateway-for-zainpay-for-woocommerce' ),
				'content' => $support_content,
			),
		);

		$admin_params = array(
			'debug' => $this->debug ? 'yes' : 'no',
			'sidebar_sections' => $sidebar_sections,
			/* translators: %s: sidebar section title */
			'toggle_label' => __( 'Toggle panel: %s', 'payment-gateway-for-zainpay-for-woocommerce' ),
		);

		wp_localize_script( 'woocommerce_pgzw_admin', 'pgzw_admin_params', $admin_params );

	}


	/**
	 * Display the payment page
	 *
	 * @param int $order_id Order ID
	 */
	public function receipt_page( $order_id ) {
		$order = wc_get_order( $order_id );

		if ( ! $order ) {
			return;
		}

		echo '<p>' . esc_html__( 'Thank you for your order, please click the button below to pay with ZainPay.', 'payment-gateway-for-zainpay-for-woocommerce' ) . '</p>';

		echo '<div id="pgzw-form">';

		if ( $this->payment_page === 'inline' ) {
			// For inline payments, show the payment form
			$this->generate_inline_form( $order );
		} else {
			// For redirect payments, show pay now button
			echo '<p><a class="button alt" href="' . esc_url( $this->get_zainpay_redirect_url( $order ) ) . '">' . esc_html__( 'Pay Now', 'payment-gateway-for-zainpay-for-woocommerce' ) . '</a></p>';
		}

		echo '<p><a class="button cancel" href="' . esc_url( $order->get_cancel_order_url() ) . '">' . esc_html__( 'Cancel order &amp; restore cart', 'payment-gateway-for-zainpay-for-woocommerce' ) . '</a></p>';

		echo '</div>';
	}

	/**
     * Generate inline payment form
     *
     * @param WC_Order $order Order object
     */
    private function generate_inline_form( $order ) {
        $pgzw_params = $this->get_pgzw_params( $order );
        
        echo '<div id="pgzw-inline-form">';
        echo '<div class="pgzw-payment-info">';
        echo '<h3>' . esc_html__( 'Complete Your Payment', 'payment-gateway-for-zainpay-for-woocommerce' ) . '</h3>';
        /* translators: %s: formatted order total */
        echo '<p>' . wp_kses_post( sprintf( __( 'You will be charged %s for this order.', 'payment-gateway-for-zainpay-for-woocommerce' ), '<strong>' . wc_price( $order->get_total() ) . '</strong>' ) ) . '</p>';
        echo '</div>';
        
        echo '<form id="pgzw-payment-form">';
        echo '<input type="hidden" id="pgzw-amount" value="' . esc_attr( $pgzw_params['amount'] ) . '" />';
        echo '<input type="hidden" id="pgzw-email" value="' . esc_attr( $pgzw_params['email'] ) . '" />';
        echo '<input type="hidden" id="pgzw-reference" value="' . esc_attr( $pgzw_params['reference'] ) . '" />';
        echo '<input type="hidden" id="pgzw-currency" value="' . esc_attr( $pgzw_params['currency'] ) . '" />';
        echo '<input type="hidden" id="pgzw-callback-url" value="' . esc_attr( $pgzw_params['callback_url'] ) . '" />';
        echo '<input type="hidden" id="pgzw-zainbox-code" value="' . esc_attr( $this->get_zainbox_code() ) . '" />';
        echo '<input type="hidden" id="pgzw-order-id" value="' . esc_attr( $order->get_id() ) . '" />';
        
        echo '<div class="pgzw-payment-actions">';
        /* translators: %s: formatted order total */
        echo '<button type="submit" id="pgzw-submit-payment" class="button alt">' . wp_kses_post( sprintf( __( 'Pay %s', 'payment-gateway-for-zainpay-for-woocommerce' ), wc_price( $order->get_total() ) ) ) . '</button>';
        echo '<a href="' . esc_url( $order->get_cancel_order_url() ) . '" class="button cancel">' . esc_html__( 'Cancel', 'payment-gateway-for-zainpay-for-woocommerce' ) . '</a>';
        echo '</div>';
        
        echo '</form>';
        echo '</div>';
    }

	/**
	 * Get ZainPay redirect URL for payment
	 *
	 * @param WC_Order $order Order object
	 * @return string Redirect URL
	 */
	private function get_zainpay_redirect_url( $order ) {
		try {
			$pgzw_params = $this->get_pgzw_params( $order );
			$pgzw_params['phone'] = $order->get_billing_phone();
			$payment_init = $this->initialize_payment( $pgzw_params );
			
			// Handle both string URL response and array response with authorization_url
			if ( $payment_init ) {
				if ( is_string( $payment_init ) && filter_var( $payment_init, FILTER_VALIDATE_URL ) ) {
					// Direct URL string response
					return $payment_init;
				} elseif ( is_array( $payment_init ) && isset( $payment_init['authorization_url'] ) ) {
					// Array response with authorization_url key
					return $payment_init['authorization_url'];
				}
			}
		} catch ( Exception $e ) {
		            /* translators: %s: error message */
	wc_add_notice( sprintf( __( 'Payment initialization failed: %s', 'payment-gateway-for-zainpay-for-woocommerce' ), $e->getMessage() ), 'error' );
		}

		return $order->get_cancel_order_url();
	}

	/**
	 * Verify ZainPay transaction
	 */
	public function verify_zainpay_transaction() {
		if ( function_exists( 'ob_get_level' ) && ob_get_level() ) {
			ob_clean();
		}

		$callback_request = array();
		$reference_input = filter_input( INPUT_GET, 'reference', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
		if ( null !== $reference_input && false !== $reference_input ) {
			$callback_request['reference'] = $reference_input;
		}
		$txn_ref_input = filter_input( INPUT_GET, 'txnRef', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
		if ( null !== $txn_ref_input && false !== $txn_ref_input ) {
			$callback_request['txnRef'] = $txn_ref_input;
		}
		$status_input = filter_input( INPUT_GET, 'status', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
		if ( null !== $status_input && false !== $status_input ) {
			$callback_request['status'] = $status_input;
		}
		$callback_url_input = filter_input( INPUT_GET, 'callBackUrl', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
		if ( null !== $callback_url_input && false !== $callback_url_input ) {
			$callback_request['callBackUrl'] = $callback_url_input;
		}
		$this->log( 'ZainPay Callback Request: ' . wp_json_encode( PGZW_Utils::sanitize_array( $callback_request ) ) );

		// Check for reference parameter (could be 'reference' or 'txnRef')
		$reference = '';
		$status = '';
		$callback_status = '';
		$successful_statuses = array( 'success', 'successful', 'completed', 'paid' );
		$pending_statuses    = array( 'pending', 'processing', 'in_progress' );
		
		// First check for direct parameters
		if ( ! empty( $callback_request['reference'] ) ) {
			$reference = sanitize_text_field( $callback_request['reference'] );
		} elseif ( ! empty( $callback_request['txnRef'] ) ) {
			$reference = sanitize_text_field( $callback_request['txnRef'] );
		}
		
		// If no direct reference found, check if parameters are embedded in callBackUrl
		if ( empty( $reference ) && ! empty( $callback_request['callBackUrl'] ) ) {
			$callback_url = sanitize_text_field( $callback_request['callBackUrl'] );
			$this->log( 'ZainPay Callback URL: ' . $callback_url );
			
			// Parse the embedded parameters from the callback URL
			$parsed_url = wp_parse_url( $callback_url );
			if ( isset( $parsed_url['query'] ) ) {
				// Handle semicolon-separated parameters (ZainPay uses semicolons instead of ampersands)
				$query_string = str_replace( ';', '&', $parsed_url['query'] );
				parse_str( $query_string, $params );
				
				if ( isset( $params['txnRef'] ) ) {
					$reference = sanitize_text_field( $params['txnRef'] );
				}
				if ( isset( $params['status'] ) ) {
					$status = sanitize_text_field( $params['status'] );
				}

				$this->log( 'ZainPay Parsed Parameters - Reference: ' . $reference . ', Status: ' . $status );
			}
		}

		if ( ! empty( $reference ) && strpos( $reference, '?' ) !== false ) {
			$reference_parts = explode( '?', $reference, 2 );
			$reference = sanitize_text_field( $reference_parts[0] );
			if ( isset( $reference_parts[1] ) && ! empty( $reference_parts[1] ) ) {
				$extra_query = str_replace( ';', '&', $reference_parts[1] );
				parse_str( $extra_query, $extra_params );
				if ( empty( $status ) && isset( $extra_params['status'] ) ) {
					$status = sanitize_text_field( $extra_params['status'] );
				}
			}
		}

		if ( ! empty( $status ) ) {
			$callback_status = strtolower( $status );
		}

		if ( empty( $reference ) ) {
			$this->log( 'ZainPay Callback Error: No reference or txnRef parameter found', 'error' );
			wc_add_notice( __( 'ZainPay transaction reference not found', 'payment-gateway-for-zainpay-for-woocommerce' ), 'error' );
			wp_safe_redirect( wc_get_checkout_url() );
			exit;
		}
		$this->log( 'ZainPay Callback Processing Reference: ' . $reference );
		
		// Extract order ID from reference using utility parser
		$order_id = PGZW_Utils::parse_order_id_from_reference( $reference );

		$this->log( 'ZainPay Callback Extracted Order ID: ' . $order_id );

		if ( ! $order_id ) {
			$this->log( 'ZainPay Callback Error: Invalid order reference format - ' . $reference, 'error' );
			wc_add_notice( __( 'Invalid order reference', 'payment-gateway-for-zainpay-for-woocommerce' ), 'error' );
			wp_safe_redirect( wc_get_checkout_url() );
			exit;
		}

		$order = wc_get_order( $order_id );

		if ( ! $order ) {
			$this->log( 'ZainPay Callback Error: Order not found for ID - ' . $order_id, 'error' );
			wc_add_notice( __( 'Order not found', 'payment-gateway-for-zainpay-for-woocommerce' ), 'error' );
			wp_safe_redirect( wc_get_checkout_url() );
			exit;
		}

		$this->log( 'ZainPay Callback Found Order: #' . $order_id . ' Status: ' . $order->get_status() );

		$cancelled_statuses = array( 'cancel', 'cancelled', 'canceled' );
		if ( ! empty( $callback_status ) && in_array( $callback_status, $cancelled_statuses, true ) ) {
			if ( ! $order->has_status( array( 'cancelled', 'failed', 'completed', 'processing' ) ) ) {
				/* translators: %s: transaction reference */
				$order->update_status( 'cancelled', sprintf( __( 'ZainPay payment was cancelled by the customer. Transaction reference: %s', 'payment-gateway-for-zainpay-for-woocommerce' ), $reference ) );
			} else {
				/* translators: %s: transaction reference */
				$order->add_order_note( sprintf( __( 'ZainPay callback received cancellation for transaction reference: %s', 'payment-gateway-for-zainpay-for-woocommerce' ), $reference ) );
			}
			wc_add_notice( __( 'Payment was cancelled.', 'payment-gateway-for-zainpay-for-woocommerce' ), 'notice' );
			wp_safe_redirect( $order->get_cancel_order_url() );
			exit;
		}

		// Check if payment has already been processed
		if ( $order->is_paid() ) {
			wp_safe_redirect( $this->get_return_url( $order ) );
			exit;
		}

		try {
			// Set ZainPay mode and token
			if ( $this->testmode ) {
				\Zainpay\SDK\Engine::setMode( \Zainpay\SDK\Engine::MODE_DEVELOPMENT );
				\Zainpay\SDK\Engine::setToken( $this->test_api_token );
			} else {
				\Zainpay\SDK\Engine::setMode( \Zainpay\SDK\Engine::MODE_PRODUCTION );
				\Zainpay\SDK\Engine::setToken( $this->live_api_token );
			}

			$card = new \Zainpay\SDK\WordPress\Card();
			$response = $card->verifyCardPaymentV2( $reference );

		$verification_payload = array(
			'succeeded'   => $response->hasSucceeded(),
			'description' => $response->getDescription(),
			'data'        => $response->getData(),
			'reference'   => $reference,
		);
		$verification_payload['data'] = is_array( $verification_payload['data'] ) ? PGZW_Utils::sanitize_array( $verification_payload['data'] ) : $verification_payload['data'];
		$this->log( 'ZainPay Callback Verify API Response: ' . wp_json_encode( $verification_payload ) );

			if ( $response->hasSucceeded() ) {
				$verification_data = $response->getData();

				// Determine payment status from data['status'] or response description
				$payment_status = '';
				if ( isset( $verification_data['status'] ) && ! empty( $verification_data['status'] ) ) {
					$payment_status = strtolower( $verification_data['status'] );
				} else {
					$payment_status = strtolower( $response->getDescription() );
				}

				if ( ! empty( $callback_status ) && ( in_array( $callback_status, $successful_statuses, true ) || in_array( $callback_status, $pending_statuses, true ) ) ) {
					if ( empty( $payment_status ) || in_array( $payment_status, array( 'not found', 'failed', 'error', 'declined' ), true ) ) {
						$payment_status = in_array( $callback_status, $successful_statuses, true ) ? 'pending' : $callback_status;
					}
				}
				
				if ( in_array( $payment_status, $successful_statuses, true ) ) {
					// Normalize amount from various response shapes
					$amount_paid = 0.0;
					$order_total = floatval( $order->get_total() );
					if ( isset( $verification_data['amount'] ) ) {
						if ( is_array( $verification_data['amount'] ) && isset( $verification_data['amount']['amount'] ) ) {
							$amount_raw = floatval( $verification_data['amount']['amount'] );
						} else {
							$amount_raw = floatval( $verification_data['amount'] );
						}
						// Normalize amount using utility (handles kobo->Naira heuristic)
						$amount_paid = PGZW_Utils::normalize_amount_for_order_total( $order_total, $amount_raw );
					}

					// Fee-tolerant payment handling: accept net amounts and record fee
					$amount_received = floatval( $amount_paid );
					$calc = PGZW_Utils::compute_net_and_fee( $order_total, $amount_received );
					$fee = $calc['fee'];
					
					// Mark order paid for full amount using transaction reference
					$order->payment_complete( $reference );
					
					// Add detailed order note: Gross, Fee, Net
					$order_currency = $order->get_currency();
					$currency_symbol = get_woocommerce_currency_symbol( $order_currency );
					$order_note = $this->format_payment_confirmation_note( $order, $order_total, $fee, $amount_received, $reference );
					$order->add_order_note( $order_note );
					
					// Save net amount and fee as order meta
					$this->save_pgzw_payment_meta( $order, $amount_received, $fee );
					
					// Reduce stock once
					if ( ! $order->get_meta( '_stock_reduced', true ) ) {
						function_exists( 'wc_reduce_stock_levels' ) ? wc_reduce_stock_levels( $order_id ) : $order->reduce_order_stock();
					}
					
					// Autocomplete if enabled
					if ( $this->autocomplete_order ) {
						$order->update_status( 'completed' );
					}
					
					// Empty cart for front-channel callback flow
					if ( function_exists( 'WC' ) && WC()->cart ) {
						WC()->cart->empty_cart();
					}
					
					wc_add_notice( __( 'Payment successful!', 'payment-gateway-for-zainpay-for-woocommerce' ), 'success' );
				} elseif ( in_array( $payment_status, $pending_statuses ) ) {
                    // Payment is still pending - set order to on-hold for manual review
                    /* translators: 1: payment status, 2: transaction reference */
                    $order->update_status( 'on-hold', sprintf( __( 'ZainPay payment is pending verification. Status: %1$s. Transaction reference: %2$s', 'payment-gateway-for-zainpay-for-woocommerce' ), $payment_status, $reference ) );
                    wc_add_notice( __( 'Your payment is being processed. You will receive confirmation once it is completed.', 'payment-gateway-for-zainpay-for-woocommerce' ), 'notice' );
                } else {
                    // Payment failed or declined
                    /* translators: %s: payment status */
                    $error_message = isset( $verification_data['message'] ) ? $verification_data['message'] : sprintf( __( 'Payment verification failed. Status: %s', 'payment-gateway-for-zainpay-for-woocommerce' ), $payment_status );
                    /* translators: %s: error message */
                    $order->update_status( 'failed', sprintf( __( 'ZainPay payment verification failed: %s', 'payment-gateway-for-zainpay-for-woocommerce' ), $error_message ) );
                    wc_add_notice( __( 'Unfortunately your order cannot be processed as the originating bank/merchant has declined your transaction. Please attempt your purchase again.', 'payment-gateway-for-zainpay-for-woocommerce' ), 'error' );
                }
			} else {
				$error_message = $response->getDescription() ?: __( 'Payment verification failed', 'payment-gateway-for-zainpay-for-woocommerce' );
				if ( ! empty( $callback_status ) && in_array( $callback_status, $successful_statuses, true ) ) {
					/* translators: 1: callback status, 2: error message */
					$order->update_status( 'on-hold', sprintf( __( 'ZainPay callback indicates success (%1$s) but verification failed: %2$s', 'payment-gateway-for-zainpay-for-woocommerce' ), $callback_status, $error_message ) );
					wc_add_notice( __( 'Payment received and awaiting confirmation.', 'payment-gateway-for-zainpay-for-woocommerce' ), 'notice' );
				} elseif ( ! empty( $callback_status ) && in_array( $callback_status, $pending_statuses, true ) ) {
					/* translators: 1: callback status, 2: error message */
					$order->update_status( 'on-hold', sprintf( __( 'ZainPay callback indicates pending (%1$s). Verification failed: %2$s', 'payment-gateway-for-zainpay-for-woocommerce' ), $callback_status, $error_message ) );
					wc_add_notice( __( 'Your payment is being processed. You will receive confirmation once it is completed.', 'payment-gateway-for-zainpay-for-woocommerce' ), 'notice' );
				} else {
					/* translators: %s: error message */
					$order->update_status( 'failed', sprintf( __( 'ZainPay payment verification failed: %s', 'payment-gateway-for-zainpay-for-woocommerce' ), $error_message ) );
					/* translators: %s: error message */
					wc_add_notice( sprintf( __( 'Payment verification failed: %s', 'payment-gateway-for-zainpay-for-woocommerce' ), $error_message ), 'error' );
				}
			}
		} catch ( Exception $e ) {
			// Log the error for debugging
			$this->log( 'ZainPay Payment Verification Error: ' . $e->getMessage(), 'error' );
			
			$error_message = $e->getMessage();
			if ( ! empty( $callback_status ) && in_array( $callback_status, $successful_statuses, true ) ) {
				/* translators: 1: callback status, 2: error message */
				$order->update_status( 'on-hold', sprintf( __( 'ZainPay callback indicates success (%1$s) but verification errored: %2$s', 'payment-gateway-for-zainpay-for-woocommerce' ), $callback_status, $error_message ) );
				wc_add_notice( __( 'Payment received and awaiting confirmation.', 'payment-gateway-for-zainpay-for-woocommerce' ), 'notice' );
			} elseif ( ! empty( $callback_status ) && in_array( $callback_status, $pending_statuses, true ) ) {
				/* translators: 1: callback status, 2: error message */
				$order->update_status( 'on-hold', sprintf( __( 'ZainPay callback indicates pending (%1$s). Verification errored: %2$s', 'payment-gateway-for-zainpay-for-woocommerce' ), $callback_status, $error_message ) );
				wc_add_notice( __( 'Your payment is being processed. You will receive confirmation once it is completed.', 'payment-gateway-for-zainpay-for-woocommerce' ), 'notice' );
			} else {
				/* translators: %s: error message */
				$order->update_status( 'failed', sprintf( __( 'ZainPay payment verification error: %s', 'payment-gateway-for-zainpay-for-woocommerce' ), $error_message ) );

				// Return user-friendly error message
				$user_error_message = __( 'Payment verification failed. Please contact support.', 'payment-gateway-for-zainpay-for-woocommerce' );
				if ( $this->testmode ) {
					$user_error_message .= ' (Debug: ' . $error_message . ')';
				}

				wc_add_notice( $user_error_message, 'error' );
			}
		}

		wp_safe_redirect( $this->get_return_url( $order ) );
		exit;
	}

	/**
     * Create order and initialize payment via AJAX for checkout.
     */
    public function create_order_and_init_payment_ajax() {
        // Verify nonce
	    if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'pgzw_inline_payment' ) ) {
	        wp_send_json_error( array( 'message' => __( 'Security check failed', 'payment-gateway-for-zainpay-for-woocommerce' ) ) );
	    }

        try {
            // Ensure cart is available and not empty
            if ( ! WC()->cart || WC()->cart->is_empty() ) {
                wp_send_json_error( array( 'message' => __( 'Your cart is empty.', 'payment-gateway-for-zainpay-for-woocommerce' ) ) );
            }

            $checkout = WC()->checkout();

            // Collect and validate posted checkout data
            $posted_data = $checkout->get_posted_data();
            $posted_data['payment_method'] = $this->id; // force our gateway

            // Create the order from current cart and posted data
            $order_id = $checkout->create_order( $posted_data );
            if ( is_wp_error( $order_id ) ) {
                wp_send_json_error( array( 'message' => $order_id->get_error_message() ) );
            }

            $order = wc_get_order( $order_id );
            if ( ! $order ) {
                wp_send_json_error( array( 'message' => __( 'Unable to create order. Please try again.', 'payment-gateway-for-zainpay-for-woocommerce' ) ) );
            }

            // Ensure payment method is set correctly
            if ( ! $order->get_payment_method() ) {
                $order->set_payment_method( $this->id );
                $order->save();
            }

            // If inline mode, return payload for frontend SDK instead of hosted URL
            if ( 'inline' === $this->payment_page ) {
                $pgzw_params = $this->get_pgzw_params( $order );
                // Recorded up front so status checks have a reference to work
                // with until the frontend reports back the one the inline SDK
                // substitutes.
                $order->update_meta_data( '_zainpay_txn_ref', $pgzw_params['reference'] );
                $order->save();
				/* translators: %s: transaction reference */
                $order->update_status( 'pending', sprintf( __( 'ZainPay payment initialized. Transaction reference: %s', 'payment-gateway-for-zainpay-for-woocommerce' ), $pgzw_params['reference'] ) );
                // Determine logo URL from site icon (fallback to plugin logo)
                $logo_url = '';
                if ( function_exists( 'get_site_icon_url' ) ) {
                    $logo_url = get_site_icon_url( 128 );
                }
                if ( empty( $logo_url ) ) {
                    $logo_url = PGZW_URL . '/assets/images/zainpay.png';
                }

                $inline = array(
                    'amount'       => $pgzw_params['amount'],
                    'txnRef'       => $pgzw_params['reference'],
                    'mobileNumber' => $order->get_billing_phone(),
                    'zainboxCode'  => $this->get_zainbox_code(),
                    'emailAddress' => $order->get_billing_email(),
                    'callBackUrl'  => $pgzw_params['callback_url'],
                    'currencyCode' => $pgzw_params['currency'],
                    'logoUrl'      => esc_url_raw( $logo_url ),
                );
                wp_send_json_success( array(
                    'inline'    => $inline,
                    'order_id'  => $order->get_id(),
                    'order_key' => $order->get_order_key(),
                    'reference' => $pgzw_params['reference'],
                ) );
            }

            // Fallback: proceed with server-side initialization (redirect flow)
			$pgzw_params = $this->get_pgzw_params( $order );
			/* translators: %s: transaction reference */
			$order->update_status( 'pending', sprintf( __( 'ZainPay payment initialized. Transaction reference: %s', 'payment-gateway-for-zainpay-for-woocommerce' ), $pgzw_params['reference'] ) );

			$payment_init = $this->initialize_payment( $pgzw_params );

			$redirect_url = null;
			if ( $payment_init ) {
				if ( is_string( $payment_init ) && filter_var( $payment_init, FILTER_VALIDATE_URL ) ) {
					$redirect_url = $payment_init;
				} elseif ( is_array( $payment_init ) && isset( $payment_init['authorization_url'] ) ) {
					$redirect_url = $payment_init['authorization_url'];
				}
			}

			if ( $redirect_url ) {
				wp_send_json_success(
					array(
						'redirect_url' => $redirect_url,
						'order_id'     => $order_id,
						'reference'    => $pgzw_params['reference'],
					)
				);
			}

			/* translators: %s: transaction reference */
			$order->update_status( 'failed', sprintf( __( 'ZainPay payment initialization failed. Reference: %s', 'payment-gateway-for-zainpay-for-woocommerce' ), $pgzw_params['reference'] ) );
			wp_send_json_error( array( 'message' => __( 'Unable to process payment. Please try again.', 'payment-gateway-for-zainpay-for-woocommerce' ) ) );
        } catch ( Exception $e ) {
            wp_send_json_error( array( 'message' => $e->getMessage() ) );
        }
    }

	/**
	 * Process inline payment via AJAX
	 */
	public function process_inline_payment_ajax() {
		
		if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'pgzw_inline_payment' ) ) {
			$this->log( 'ZainPay AJAX: Nonce verification failed', 'error' );
			wp_send_json_error( array( 'message' => __( 'Security check failed', 'payment-gateway-for-zainpay-for-woocommerce' ) ) );
		}

		$payment_data = isset( $_POST['payment_data'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['payment_data'] ) ) : array();
		$order_id = intval( $payment_data['order_id'] ?? 0 );
		
		if ( ! $order_id ) {
			// Try to get order ID from reference using utility parser
			$reference = sanitize_text_field( $payment_data['reference'] ?? '' );
			$order_id  = PGZW_Utils::parse_order_id_from_reference( $reference );
		}

		$order = wc_get_order( $order_id );

		if ( ! $order ) {
			wp_send_json_error( array( 'message' => __( 'Order not found', 'payment-gateway-for-zainpay-for-woocommerce' ) ) );
		}

		// If inline mode, return inline payload immediately for frontend SDK
		if ( 'inline' === $this->payment_page ) {
			$pgzw_params = $this->get_pgzw_params( $order );
			// Store the transaction reference in the order meta and as transaction ID
			$txn_ref = $pgzw_params['reference'];
			$order->update_meta_data('_zainpay_txn_ref', $txn_ref);
			$order->set_transaction_id($txn_ref);
			
			if ( ! in_array( $order->get_status(), array( 'pending', 'on-hold', 'processing', 'completed' ), true ) ) {
				/* translators: %s: transaction reference */
				$order->update_status( 'pending', sprintf( __( 'ZainPay payment initialized. Transaction reference: %s', 'payment-gateway-for-zainpay-for-woocommerce' ), $txn_ref ) );
			} else {
				// Add a note even if status is already pending
				/* translators: %s: transaction reference */
				$order->add_order_note( sprintf( __( 'ZainPay payment initialized. Transaction reference: %s', 'payment-gateway-for-zainpay-for-woocommerce' ), $txn_ref ) );
			}
			
			// Save the order to persist the transaction ID and meta
			$order->save();
			
			// Determine logo URL from site icon (fallback to plugin logo)
			$logo_url = '';
			if ( function_exists( 'get_site_icon_url' ) ) {
				$logo_url = get_site_icon_url( 128 );
			}
			if ( empty( $logo_url ) ) {
				$logo_url = PGZW_URL . '/assets/images/zainpay.png';
			}
			$inline = array(
				'amount'       => $pgzw_params['amount'],
				'txnRef'       => $pgzw_params['reference'],
				'mobileNumber' => $order->get_billing_phone(),
				'zainboxCode'  => $this->get_zainbox_code(),
				'emailAddress' => $order->get_billing_email(),
				'callBackUrl'  => $pgzw_params['callback_url'],
				'currencyCode' => $pgzw_params['currency'],
				'logoUrl'      => esc_url_raw( $logo_url ),
			);
			wp_send_json_success( array(
				'inline'    => $inline,
				'order_id'  => $order->get_id(),
				'order_key' => $order->get_order_key(),
				'reference' => $pgzw_params['reference'],
			) );
		}

		try {
			// Initialize ZainPay SDK
			if ( $this->testmode ) {
				\Zainpay\SDK\Engine::setMode( \Zainpay\SDK\Engine::MODE_DEVELOPMENT );
				\Zainpay\SDK\Engine::setToken( $this->test_api_token );
			} else {
				\Zainpay\SDK\Engine::setMode( \Zainpay\SDK\Engine::MODE_PRODUCTION );
				\Zainpay\SDK\Engine::setToken( $this->live_api_token );
			}

			$pgzw_params = $this->get_pgzw_params( $order );

			// Initialize card payment
			$card = new \Zainpay\SDK\WordPress\Card();
			$response = $card->initializeCardPayment(
				$pgzw_params['amount'],
				$pgzw_params['reference'],
				$pgzw_params['email'],
				$order->get_billing_phone(),
				$this->get_zainbox_code(),
				$pgzw_params['callback_url']
			);

			if ( $response->hasSucceeded() ) {
				$data = $response->getData();
				$redirect_url = null;
				
				// Handle different response formats from ZainPay API
				if ( is_string( $data ) && filter_var( $data, FILTER_VALIDATE_URL ) ) {
					// ZainPay returns redirect URL directly as string
					$redirect_url = $data;
				} elseif ( is_array( $data ) && isset( $data['authorization_url'] ) ) {
					// Alternative format with authorization_url key
					$redirect_url = $data['authorization_url'];
				} elseif ( is_array( $data ) && isset( $data['data'] ) && filter_var( $data['data'], FILTER_VALIDATE_URL ) ) {
					// Nested data structure
					$redirect_url = $data['data'];
				}
				
				if ( $redirect_url ) {
					// Update order status to pending payment
					/* translators: %s: transaction reference */
					$order->update_status( 'pending', sprintf( __( 'ZainPay payment initialized. Transaction reference: %s', 'payment-gateway-for-zainpay-for-woocommerce' ), $pgzw_params['reference'] ) );
					
					wp_send_json_success( array(
						'message'      => __( 'Payment initialized successfully!', 'payment-gateway-for-zainpay-for-woocommerce' ),
						'redirect_url' => $redirect_url,
						'order_id'     => $order->get_id(),
						'reference'    => $pgzw_params['reference'],
					) );
				} else {
					$error_message = is_array( $data ) && isset( $data['message'] ) ? $data['message'] : __( 'Payment initialization failed - no redirect URL', 'payment-gateway-for-zainpay-for-woocommerce' );
                    /* translators: %s: error message */
                    $order->update_status( 'failed', sprintf( __( 'ZainPay payment initialization failed: %s', 'payment-gateway-for-zainpay-for-woocommerce' ), $error_message ) );
					
					wp_send_json_error( array( 'message' => $error_message ) );
				}
			} else {
				$error_message = $response->getDescription() ?: __( 'Payment processing failed', 'payment-gateway-for-zainpay-for-woocommerce' );
                /* translators: %s: error message */
                $order->update_status( 'failed', sprintf( __( 'ZainPay inline payment failed: %s', 'payment-gateway-for-zainpay-for-woocommerce' ), $error_message ) );
				
				wp_send_json_error( array( 'message' => $error_message ) );
			}

		} catch ( Exception $e ) {
			// Log the error for debugging
			$this->log( 'ZainPay Inline Payment Error: ' . $e->getMessage(), 'error' );
			
			$error_message = $e->getMessage();
			/* translators: %s: error message */
			$order->update_status( 'failed', sprintf( __( 'ZainPay inline payment error: %s', 'payment-gateway-for-zainpay-for-woocommerce' ), $error_message ) );
			
			// Return user-friendly error message
			$user_error_message = __( 'Payment processing failed. Please try again or contact support.', 'payment-gateway-for-zainpay-for-woocommerce' );
			if ( $this->testmode ) {
				$user_error_message .= ' (Debug: ' . $error_message . ')';
			}
			
			wp_send_json_error( array( 'message' => $user_error_message ) );
		}
	}

	/**
	 * AJAX: Record the transaction reference the inline SDK generated.
	 *
	 * The inline SDK overwrites the reference it is handed with one of its own
	 * before calling ZainPay, so the reference the plugin generated never
	 * reaches them. The frontend reads the substituted value back off the
	 * payload object and posts it here so verification, the callback and the
	 * webhook can all resolve the order.
	 */
	public function record_txn_ref_ajax() {

		if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'pgzw_inline_payment' ) ) {
			wp_send_json_error( array( 'message' => __( 'Security check failed', 'payment-gateway-for-zainpay-for-woocommerce' ) ) );
		}

		$order_id  = isset( $_POST['order_id'] ) ? absint( wp_unslash( $_POST['order_id'] ) ) : 0;
		$order_key = isset( $_POST['order_key'] ) ? sanitize_text_field( wp_unslash( $_POST['order_key'] ) ) : '';
		$txn_ref   = isset( $_POST['txn_ref'] ) ? sanitize_text_field( wp_unslash( $_POST['txn_ref'] ) ) : '';

		$order = $order_id ? wc_get_order( $order_id ) : false;

		// The order key is what proves the caller owns this (possibly guest) order.
		if ( ! $order || '' === $order_key || ! hash_equals( $order->get_order_key(), $order_key ) ) {
			wp_send_json_error( array( 'message' => __( 'Order not found', 'payment-gateway-for-zainpay-for-woocommerce' ) ) );
		}

		if ( ! preg_match( self::REFERENCE_PATTERN, $txn_ref ) ) {
			wp_send_json_error( array( 'message' => __( 'Invalid transaction reference', 'payment-gateway-for-zainpay-for-woocommerce' ) ) );
		}

		if ( $order->is_paid() ) {
			wp_send_json_error( array( 'message' => __( 'This order has already been paid.', 'payment-gateway-for-zainpay-for-woocommerce' ) ) );
		}

		$order->update_meta_data( '_zainpay_txn_ref', $txn_ref );
		$order->set_transaction_id( $txn_ref );
		$order->save();

		$this->log( sprintf( 'Recorded inline SDK transaction reference %s for Order #%d', $txn_ref, $order_id ) );

		wp_send_json_success( array( 'reference' => $txn_ref ) );

	}

	/**
	 * AJAX: Check payment/order status for polling from frontend
	 */
	public function check_payment_status_ajax() {
		$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
		if ( empty( $nonce ) || ( ! wp_verify_nonce( $nonce, 'pgzw_check_payment_status' ) && ! wp_verify_nonce( $nonce, 'pgzw_inline_payment' ) ) ) {
			wp_send_json_error( array( 'status' => 'error', 'message' => __( 'Security check failed', 'payment-gateway-for-zainpay-for-woocommerce' ) ) );
		}

		$order_id            = isset( $_POST['order_id'] ) ? absint( wp_unslash( $_POST['order_id'] ) ) : 0;
		$requested_reference = isset( $_POST['reference'] ) ? sanitize_text_field( wp_unslash( $_POST['reference'] ) ) : '';

		if ( ! $order_id && $requested_reference ) {
			$order_id = PGZW_Utils::parse_order_id_from_reference( $requested_reference );
		}

		$order = $order_id ? wc_get_order( $order_id ) : false;

		if ( ! $order ) {
			wp_send_json_error( array( 'status' => 'error', 'message' => __( 'Order not found', 'payment-gateway-for-zainpay-for-woocommerce' ) ) );
		}
		
		if ( is_user_logged_in() ) {
			$current_user_id = get_current_user_id();
			if ( $order->get_user_id() && (int) $order->get_user_id() !== (int) $current_user_id ) {
				wp_send_json_error( array( 'status' => 'error', 'message' => __( 'Order not found', 'payment-gateway-for-zainpay-for-woocommerce' ) ) );
			}
		}

		// Only the reference recorded against the order is trusted for
		// verification. Accepting one from the client would let a caller
		// settle this order against somebody else's successful transaction.
		$reference  = $order->get_meta( '_zainpay_txn_ref', true );
		$reference  = is_string( $reference ) ? $reference : '';

		$status = $order->get_status();

		if ( in_array( $status, array( 'success', 'processing', 'completed' ), true ) ) {
			wp_send_json_success( array(
				'status'       => $status,
				'redirect_url' => $this->get_return_url( $order ),
			) );
		}

		if ( in_array( $status, array( 'failed', 'cancelled', 'refunded' ), true ) ) {
			wp_send_json_error( array(
				'status'  => $status,
				'message' => __( 'Payment was not successful.', 'payment-gateway-for-zainpay-for-woocommerce' ),
			) );
		}

		// Always attempt direct API verification if we have a reference
		if ( ! empty( $reference ) ) {
			// Perform direct API verification
			
			$this->log( 'Performing direct API verification for reference: ' . $reference );
			$verification = $this->verify_transaction( $reference );
			
			if ( $verification ) {
				// If payment is successful according to API, update order status
				if ( isset( $verification['is_successful'] ) && $verification['is_successful'] ) {
					$amount_paid = floatval( $verification['amount'] ); // Amount net from provider
					$order_total = floatval( $order->get_total() );

					// Compute net and fee using shared utility for consistency
					$calc = PGZW_Utils::compute_net_and_fee( $order_total, $amount_paid );
					$amount_paid = $calc['net'];
					$fee = $calc['fee'];
					$currency_symbol = get_woocommerce_currency_symbol( $order->get_currency() );
					
					// Add detailed order note showing gross, fee, and net amounts
					$order_note = $this->format_payment_confirmation_note( $order, $order_total, $fee, $amount_paid, $reference );
					
					// Save net amount and fee as order meta
					$this->save_pgzw_payment_meta( $order, $amount_paid, $fee );
					
					// If net amount plus fee equals gross amount, mark as complete payment
					if ( abs($amount_paid + $fee - $order_total) < 0.01 ) {
						$order->payment_complete( $reference );
						
						// Add the detailed fee note
						$order->add_order_note( $order_note );
						
						// Determine final status based on autocomplete setting
						$status = 'processing';
						if ( $this->autocomplete_order ) {
							$order->update_status( 'completed' );
							$status = 'completed';
						}
						
						wp_send_json_success( array(
							'status'       => $status,
							'redirect_url' => $this->get_return_url( $order ),
						) );
					} else if ( $amount_paid < $order_total ) {
						/* translators: %1$s: amount paid, %2$s: order total */
						$order->update_status( 'on-hold', sprintf( __( 'Payment verification successful but amount paid (%1$s) is less than order total (%2$s).', 'payment-gateway-for-zainpay-for-woocommerce' ), wc_price( $amount_paid ), wc_price( $order_total ) ) );
						
						// Add the detailed fee note separately
						$order->add_order_note( $order_note );
						wp_send_json_success( array(
							'status'       => 'on-hold',
							'redirect_url' => $this->get_return_url( $order ),
						) );
					} else {
						$order->payment_complete( $reference );
						/* translators: %s: transaction reference */
						$order->add_order_note( sprintf( __( 'ZainPay payment verified via direct API check. Transaction reference: %s', 'payment-gateway-for-zainpay-for-woocommerce' ), $reference ) );
						
						// Determine final status based on autocomplete setting
						$status = 'processing';
						if ( $this->autocomplete_order ) {
							$order->update_status( 'completed' );
							$status = 'completed';
						}
						
						wp_send_json_success( array(
							'status'       => $status,
							'redirect_url' => $this->get_return_url( $order ),
						) );
					}
				} elseif ( isset( $verification['is_pending'] ) && $verification['is_pending'] && isset( $_POST['from_callback'] ) && absint( wp_unslash( $_POST['from_callback'] ) ) === 1 ) {
					// If payment is still pending according to API but we're coming from callback, redirect anyway
					$this->log( 'Payment still pending according to API, but redirecting user to thank you page as requested' );
					wp_send_json_success( array(
						'status'       => 'pending',
						'redirect_url' => $this->get_return_url( $order ),
					) );
				}
			}
		}

		// Handle various order statuses after API verification attempt
		
		// If order is on-hold, allow redirect to order received page
		if ( 'on-hold' === $status ) {
			wp_send_json_success( array(
				'status'       => 'on-hold',
				'redirect_url' => $this->get_return_url( $order ),
			) );
		}

		// For inline flow, if still pending after user completes popup, return redirect_url so frontend can navigate
		// Only do this when explicitly coming from the inline popup callback (from_callback=1)
		$from_callback = isset( $_POST['from_callback'] ) && absint( wp_unslash( $_POST['from_callback'] ) ) === 1;
		if ( 'pending' === $status && $from_callback ) {
			$this->log( 'Payment still pending but user completed popup flow, redirecting to thank you page' );
			wp_send_json_success( array(
				'status'       => $status,
				'redirect_url' => $this->get_return_url( $order ),
			) );
		}

		// Still pending; keep polling
		wp_send_json_success( array( 'status' => $status ) );
	}

}
