<?php

/**
 * Bani WooCommerce Payments.
 *
 * Provides a Bani Payments Payment Gateway.
 *
 * @class       WC_Gateway_Bani
 * @extends     WC_Payment_Gateway
 * @version     2.1.0
 * @package     WooCommerce/Classes/Payment
 */
class WC_Gateway_Bani extends WC_Payment_Gateway
{

	/**
	 * Constructor for the gateway.
	 */
	/**
	 * Is test mode active?
	 *
	 * @var bool
	 */
	public $testmode;

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

	/**
	 * Should custom metadata be enabled?
	 *
	 * @var bool
	 */
	public $custom_metadata;


	/**
	 * Should show user full name be enabled?
	 *
	 * @var bool
	 */
	public $show_username;



	/**
	 * Should show user account name be enabled?
	 *
	 * @var bool
	 */
	public $show_user_account_name;



	/**
	 * Should the order id be sent as a custom metadata to Bani?
	 *
	 * @var bool
	 */
	public $meta_order_id;
	/**
	 * Should the order items be sent as a custom metadata to Bani?
	 *
	 * @var bool
	 */
	public $meta_products;

	/**
	 * Should the billing address be sent as a custom metadata to Bani?
	 *
	 * @var bool
	 */
	public $meta_billing_address;

	/**
	 * API public key
	 *
	 * @var string
	 */
	public $public_key;
	/**
	 * Should the shipping address be sent as a custom metadata to Bani?
	 *
	 * @var bool
	 */
	public $meta_shipping_address;


	public function __construct()
	{
		// Setup general properties.
		$this->setup_properties();
		$this->id                 = 'bani';

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

		// Get settings.
		$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->test_public_key = $this->get_option('test_public_key');
		$this->live_public_key = $this->get_option('live_public_key');
		$this->autocomplete_order = $this->get_option('autocomplete_order') === 'yes' ? true : false;
		$this->remove_cancel_order_button = $this->get_option('remove_cancel_order_button') === 'yes' ? true : false;

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

		$this->meta_order_id         = $this->get_option('meta_order_id') === 'yes' ? true : false;
		$this->meta_products         = $this->get_option('meta_products') === 'yes' ? true : false;
		$this->meta_billing_address  = $this->get_option('meta_billing_address') === 'yes' ? true : false;
		$this->meta_shipping_address = $this->get_option('meta_shipping_address') === 'yes' ? true : false;

		$this->public_key = $this->testmode ? $this->test_public_key : $this->live_public_key;

		// 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_wc_gateway_bani', array($this, 'verify_bani_transaction'));
		// Security violation reporting
		add_action('wp_ajax_bani_report_security_violation', array($this, 'handle_security_violation_report'));
		add_action('wp_ajax_nopriv_bani_report_security_violation', array($this, 'handle_security_violation_report'));
		// Amount tampering reporting
		add_action('wp_ajax_bani_report_amount_tampering', array($this, 'handle_amount_tampering_report'));
		add_action('wp_ajax_nopriv_bani_report_amount_tampering', array($this, 'handle_amount_tampering_report'));
	}



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

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

		// Check required fields.
		if (!($this->public_key)) {
			echo '<div class="error"><p>' . sprintf(
				__(
					'Please enter your Bani merchant details <a href="%s">here</a> to be able to use the Bani WooCommerce plugin.',
					'bani-payments-for-woocommerce'
				),
				admin_url('admin.php?page=wc-settings&tab=checkout&section=bani')
			) . '</p></div>';
			return;
		}
	}

	/**
	 * Check if Bani gateway is enabled.
	 *
	 * @return bool
	 */
	public function is_available()
	{

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

			if (!($this->public_key)) {

				return false;
			}

			return true;
		}

		return false;
	}

	/**
	 * Admin Panel Options.
	 */
	public function admin_options()
	{

?>

		<h2><?php _e('Bani', 'bani-payments-for-woocommerce'); ?>
			<?php
			if (function_exists('wc_back_link')) {
				wc_back_link(__('Return to payments', 'bani-payments-for-woocommerce'), admin_url('admin.php?page=wc-settings&tab=checkout'));
			}
			?>
		</h2>

		<h4 style="margin-bottom: 10px;">
			<strong><?php printf(__('To get started <a href="%1$s" target="_blank" rel="noopener noreferrer">Create your free</a> Bani account, and <a href="%2$s" target="_blank">get your API keys</a>.', 'bani-payments-for-woocommerce'), 'https://bani.africa/', 'https://app.bani.africa/dashboard/settings'); ?></strong>
		</h4>
		<h4>
			<strong><?php printf(__('Optional: To avoid situations where bad network makes it impossible to verify transactions, set your webhook URL <a href="%1$s" target="_blank" rel="noopener noreferrer">here</a>', 'bani-payments-for-woocommerce'), 'https://app.bani.africa/dashboard/settings'); ?></strong>
		</h4>

<?php

		echo '<table class="form-table">';
		$this->generate_settings_html();
		echo '</table>';
	}

	/**
	 * Setup general properties for the gateway.
	 */
	protected function setup_properties()
	{
		$this->id                 = 'bani';
		$this->icon               = apply_filters('woocommerce_bani_icon', WC_HTTPS::force_https_url(plugins_url('assets/images/bani.svg', WC_BANI_MAIN_FILE)));
		$this->method_title       = __('Bani', 'bani-payments-for-woocommerce');
		$this->method_description =  sprintf(__('Start accepting bank transfer, cryptocurrency, and mobile money payments from customers in Africa today. <a href="%1$s" target="_blank">Create a free</a> Bani account, and <a href="%2$s" target="_blank">get your API keys</a>.', 'bani-payments-for-woocommerce'), 'https://bani.africa/', 'https://app.bani.africa/dashboard/settings');
		$this->has_fields         = false;
	}

	/**
	 * Initialise Gateway Settings Form Fields.
	 */
	public function init_form_fields()
	{
		$this->form_fields = array(
			'enabled'            => array(
				'title'       => __('Enable/Disable', 'bani-payments-for-woocommerce'),
				'label'       => __('Enable Bani Payments', 'bani-payments-for-woocommerce'),
				'type'        => 'checkbox',
				'description' => __('Enable Bani as a payment option on the checkout page.', 'bani-payments-for-woocommerce'),
				'default'     => 'no',
				'desc_tip'    => true,
			),
			'title'              => array(
				'title'       => __('Title', 'bani-payments-for-woocommerce'),
				'type'        => 'text',
				'description' => __('Bani payments description that the customer will see on your checkout.', 'bani-payments-for-woocommerce'),
				'default'     => __('Bank transfer payments/Mobile money/Cryptocurrency.', 'bani-payments-for-woocommerce'),
				'desc_tip'    => true,
			),
			'description'        => array(
				'title'       => __('Description', 'bani-payments-for-woocommerce'),
				'type'        => 'textarea',
				'description' => __('Bani payments description that the customer will see on your website.', 'bani-payments-for-woocommerce'),
				'default'     => __('Pay using bank transfer, mobile money, and cryptocurrency.', 'bani-payments-for-woocommerce'),
				'desc_tip'    => true,
			),
			'testmode'            => array(
				'title'       => __('Test Mode', 'bani-payments-for-woocommerce'),
				'label'       => __('Enable Test Mode', 'bani-payments-for-woocommerce'),
				'type'        => 'checkbox',
				'description' => __('Test mode enables you to test payments before going live. <br />Once the LIVE MODE is enabled on your Bani account uncheck this.', 'bani-payments-for-woocommerce'),
				'default'     => 'yes',
				'desc_tip'    => true,
			),
			'test_public_key'                  => array(
				'title'       => __('Test Public Key', 'bani-payments-for-woocommerce'),
				'type'        => 'text',
				'description' => __('Enter your Test Merchant Public Key here.', 'bani-payments-for-woocommerce'),
				'default'     => '',
			),
			'live_public_key'                  => array(
				'title'       => __('Live Public Key', 'bani-payments-for-woocommerce'),
				'type'        => 'text',
				'description' => __('Enter your Live Merchant Public Key here.', 'bani-payments-for-woocommerce'),
				'default'     => '',
			),
			'remove_cancel_order_button'       => array(
				'title'       => __('Remove Cancel Order & Restore Cart Button', 'bani-payments-for-woocommerce'),
				'label'       => __('Remove the cancel order & restore cart button on the pay for order page', 'bani-payments-for-woocommerce'),
				'type'        => 'checkbox',
				'description' => '',
				'default'     => 'no',
			),
			'autocomplete_order'               => array(
				'title'       => __('Autocomplete Order After Payment', 'bani-payments-for-woocommerce'),
				'label'       => __('Autocomplete Order', 'bani-payments-for-woocommerce'),
				'type'        => 'checkbox',
				'class'       => 'wc-paystack-autocomplete-order',
				'description' => __('If enabled, the order will be marked as complete after successful payment', 'bani-payments-for-woocommerce'),
				'default'     => 'no',
				'desc_tip'    => true,
			),

			'custom_metadata'                  => array(
				'title'       => __('Custom Metadata', 'bani-payments-for-woocommerce'),
				'label'       => __('Enable Custom Metadata', 'bani-payments-for-woocommerce'),
				'type'        => 'checkbox',
				'class'       => 'wc-bani-metadata',
				'description' => __('If enabled, you will be able to send more information about the order to Bani.', 'bani-payments-for-woocommerce'),
				'default'     => 'no',
				'desc_tip'    => true,
			),
			'show_username'                  => array(
				'title'       => __("Show User's Full Name Instead of Phone Number", 'bani-payments-for-woocommerce'),
				'label'       => __("Show User's Full Name", 'bani-payments-for-woocommerce'),
				'type'        => 'checkbox',
				'class'       => 'wc-bani-username',
				'description' => __("Check this box to show the user's full name in the checkout widget's header while hiding their phone number.", 'bani-payments-for-woocommerce'),
				'default'     => 'no',
				'desc_tip'    => true,
			),

			'show_user_account_name'                  => array(
				'title'       => __('Show User Account Name', 'bani-payments-for-woocommerce'),
				'label'       => __('Show User Account Name', 'bani-payments-for-woocommerce'),
				'type'        => 'checkbox',
				'class'       => 'wc-bani-user-account-name',
				'description' => __("Selecting this checkbox will display the user's full name exclusively within the bank transfer account number field.", 'bani-payments-for-woocommerce'),
				'default'     => 'no',
				'desc_tip'    => true,
			),
			'meta_order_id'                    => array(
				'title'       => __('Order ID', 'bani-payments-for-woocommerce'),
				'label'       => __('Send Order ID', 'bani-payments-for-woocommerce'),
				'type'        => 'checkbox',
				'class'       => 'wc-bani-meta-order-id',
				'description' => __('If checked, the Order ID will be sent to Bani', 'bani-payments-for-woocommerce'),
				'default'     => 'no',
				'desc_tip'    => true,
			),
			'meta_billing_address'             => array(
				'title'       => __('Order Billing Address', 'bani-payments-for-woocommerce'),
				'label'       => __('Send Order Billing Address', 'bani-payments-for-woocommerce'),
				'type'        => 'checkbox',
				'class'       => 'wc-bani-meta-billing-address',
				'description' => __('If checked, the order billing address will be sent to Bani', 'bani-payments-for-woocommerce'),
				'default'     => 'no',
				'desc_tip'    => true,
			),
			'meta_shipping_address'            => array(
				'title'       => __('Order Shipping Address', 'bani-payments-for-woocommerce'),
				'label'       => __('Send Order Shipping Address', 'bani-payments-for-woocommerce'),
				'type'        => 'checkbox',
				'class'       => 'wc-bani-meta-shipping-address',
				'description' => __('If checked, the order shipping address will be sent to Bani', 'bani-payments-for-woocommerce'),
				'default'     => 'no',
				'desc_tip'    => true,
			),
			'meta_products'                    => array(
				'title'       => __('Product(s) Purchased', 'bani-payments-for-woocommerce'),
				'label'       => __('Send Product(s) Purchased', 'bani-payments-for-woocommerce'),
				'type'        => 'checkbox',
				'class'       => 'wc-bani-meta-products',
				'description' => __('If checked, the product(s) purchased will be sent to Bani', 'bani-payments-for-woocommerce'),
				'default'     => 'no',
				'desc_tip'    => true,
			),


		);
	}

	/**
	 * Payment form on checkout page
	 */
	public function payment_fields()
	{

		if ($this->description) {
			$desc = wpautop(esc_html(wptexturize($this->description)));
			$desc = str_replace('<p>', '', $desc);
			$desc = str_replace('</p>', '', $desc);
			echo esc_html($desc);
		}

		if (!is_ssl()) {
			return;
		}
	}

	/**
	 * Outputs scripts used for bani payment.
	 */

	public function payment_scripts()
	{
		if (!is_checkout_pay_page()) {
			return;
		}

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

		$order_key = sanitize_url(urldecode($_GET['key']));
		$order_key = str_replace("http://", "", $order_key);
		$order_id  = absint(get_query_var('order-pay'));

		$order = wc_get_order($order_id);
		$payment_method = method_exists($order, 'get_payment_method') ? $order->get_payment_method() : $order->payment_method;

		if ($this->id !== $payment_method) {
			return;
		}

		// SECURITY: Verify app.min.js file integrity before loading
		if ( ! $this->verify_bani_widget_integrity() ) {
			// Log security incident
			error_log( 'BANI SECURITY ALERT: app.min.js file integrity check failed. Possible file tampering detected.' );

			// Notify admin
			$this->send_security_alert_to_admin( 'File Integrity Violation', 'The Bani payment widget file (app.min.js) has been modified and may be compromised.' );

			// Block payment processing and show error to user
			wc_add_notice( __( 'Payment processing is temporarily unavailable due to a security issue. Please contact the site administrator.', 'bani-payments-for-woocommerce' ), 'error' );
			return;
		}

		wp_enqueue_script('jquery');

		wp_enqueue_script('bani', plugins_url('assets/js/app.min.js', WC_BANI_MAIN_FILE), array('jquery'), WC_BANI_VERSION, true);

		wp_enqueue_script('wc_bani', plugins_url('assets/js/bani.min' . '.js', WC_BANI_MAIN_FILE), array('jquery', 'bani'), WC_BANI_VERSION, true);


		$bani_params = array(
			'merchantKey' => $this->public_key,
		);


		if (is_checkout_pay_page() && get_query_var('order-pay')) {

			$email         = method_exists($order, 'get_billing_email') ? $order->get_billing_email() : $order->billing_email;
			$amount        = $order->get_total() * 100;
			$txnref        = $order_id . '_' . time();
			$the_order_id  = method_exists($order, 'get_id') ? $order->get_id() : $order->id;
			$the_order_key = method_exists($order, 'get_order_key') ? $order->get_order_key() : $order->order_key;
			$currency      = method_exists($order, 'get_currency') ? $order->get_currency() : $order->order_currency;
			$first_name = method_exists($order, 'get_billing_first_name') ? $order->get_billing_first_name() : $order->billing_first_name;
			$last_name  = method_exists($order, 'get_billing_last_name') ? $order->get_billing_last_name() : $order->billing_last_name;
			$billing_phone = method_exists($order, 'get_billing_phone') ? $order->get_billing_phone() : $order->billing_phone;
			$display_username        = $this->show_username;
			$display_user_account_name        =  $this->show_user_account_name;

			if ($the_order_id == $order_id && $the_order_key == $order_key) {
				$bani_params['email']    = sanitize_email($email);
				$bani_params['amount']   = $amount;
				$bani_params['txnref']   = $txnref;
				$bani_params['currency'] = $currency;
				$bani_params['phoneNumber'] = $billing_phone;
				$bani_params['firstName'] = $first_name;
				$bani_params['lastName'] = $last_name;
				$bani_params['showUserName'] = $display_username;
				$bani_params['showUserAccountName'] = $display_user_account_name;
			}

			$custom_metadata_data = array();
			if ($this->custom_metadata) {

				if ($this->meta_order_id) {

					$custom_metadata_data['meta_order_id'] = $order_id;
				}
				if ($this->meta_billing_address) {
					$billing_address = $order->get_formatted_billing_address();
					$billing_address = esc_html(preg_replace('#<br\s*/?>#i', ', ', $billing_address));
					$custom_metadata_data['meta_billing_address'] = $billing_address;
				}

				if ($this->meta_shipping_address) {
					$shipping_address = $order->get_formatted_shipping_address();
					$shipping_address = esc_html(preg_replace('#<br\s*/?>#i', ', ', $shipping_address));

					if (empty($shipping_address)) {

						$billing_address = $order->get_formatted_billing_address();
						$billing_address = esc_html(preg_replace('#<br\s*/?>#i', ', ', $billing_address));

						$shipping_address = $billing_address;
					}


					$custom_metadata_data['meta_shipping_address'] = $shipping_address;
				}



				if ($this->meta_products) {

					$line_items = $order->get_items();

					$products = '';

					foreach ($line_items as $item_id => $item) {
						$name      = $item['name'];
						$quantity  = $item['qty'];
						$products .= $name . ' (Qty: ' . $quantity . ')';
						$products .= ' | ';
					}

					$products = rtrim($products, ' | ');

					$custom_metadata_data['meta_products'] = $products;
				}
			}
			$custom_metadata_data['order_ref'] = $txnref;
			$bani_params['metadata'] = $custom_metadata_data;

			// SECURITY: Store expected payment amount and generate signature
			// This prevents attackers from manipulating the amount via postMessage
			$order->update_meta_data( '_bani_txn_ref', $txnref );
			$order->update_meta_data( '_bani_expected_amount', $amount );
			$order->update_meta_data( '_bani_expected_currency', $currency );

			// Generate cryptographic signature of payment data
			$payment_signature = $this->generate_payment_signature( array(
				'order_id' => $order_id,
				'amount' => $amount,
				'currency' => $currency,
				'txnref' => $txnref,
				'email' => $email,
			) );

			$order->update_meta_data( '_bani_payment_signature', $payment_signature );
			$order->save();

			// Add signature to client-side parameters for validation
			$bani_params['paymentSignature'] = $payment_signature;
			$bani_params['orderId'] = $order_id;
		}



		wp_localize_script('wc_bani', 'wc_bani_params', $bani_params);
	}

	/**
	 * Load admin scripts.
	 */
	public function admin_scripts()
	{

		if ('woocommerce_page_wc-settings' !== get_current_screen()->id) {
			return;
		}

		$suffix = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';

		$bani_admin_params = array(
			'plugin_url' => WC_BANI_URL,
		);

		wp_enqueue_script('wc_bani_admin', plugins_url('assets/js/bani-admin' . $suffix . '.js', WC_BANI_MAIN_FILE), array(), WC_BANI_VERSION, true);

		wp_localize_script('wc_bani_admin', 'wc_bani_admin_params', $bani_admin_params);
	}

	/**
	 * Process the payment and return the result.
	 *
	 * @param int $order_id Order ID.
	 * @return array|void
	 */
	public function process_payment($order_id)
	{
		$order = wc_get_order($order_id);
		if ($order->get_total() > 0) {
			return array(
				'result'   => 'success',
				'redirect' => $order->get_checkout_payment_url(true),
			);
		}
	}



	/**
	 * Displays the payment page.
	 *
	 * @param $order_id
	 */
	public function receipt_page($order_id)
	{

		$order = wc_get_order($order_id);

		echo '<div id="wc-bani-form">';

		echo '<p>' . __('Thank you for your order, please click the button below to pay with Bani.', 'bani-payments-for-woocommerce') . '</p>';

		echo '<div id="bani_form"><form id="order_review" method="post" action="' . WC()->api_request_url('WC_Gateway_Bani') . '"></form><button class="button" id="bani-payment-button">' . __('Pay Now', 'bani-payments-for-woocommerce') . '</button>';

		if (!$this->remove_cancel_order_button) {
			echo '  <a class="button cancel" id="bani-cancel-payment-button" href="' . esc_url($order->get_cancel_order_url()) . '">' . __('Cancel order &amp; restore cart', 'bani-payments-for-woocommerce') . '</a></div>';
		}

		echo '</div>';
	}

	/**
	 * Verify Bani payment.
	 */
	public function verify_bani_transaction()
	{

		if (isset($_REQUEST['bani_txnref'])) {
			$bani_txn_ref = sanitize_text_field($_REQUEST['bani_txnref']);
			$bani_txn_status = sanitize_text_field($_REQUEST['bani_txnstatus']);
			$bani_txn_type = sanitize_text_field($_REQUEST['bani_txntype']);
		} elseif (isset($_REQUEST['reference'])) {
			$bani_txn_ref = sanitize_text_field($_REQUEST['reference']);
		} else {
			$bani_txn_ref = '';
			$bani_txn_status = '';
			$bani_txn_type = '';
		}

		function RemoveSpecialChar($str)
		{

			// Using str_replace() function 
			// to replace the word 
			$res = str_replace('/', '', $str);

			// Returning the result 
			return $res;
		}
		$bani_txn_ref =  RemoveSpecialChar($bani_txn_ref);
		$bani_txn_status =  RemoveSpecialChar($bani_txn_status);
		$bani_txn_type =  RemoveSpecialChar($bani_txn_type);

		@ob_clean();

		if ($bani_txn_ref) {
			$cryptoUrl = "/partner/collection/coin_payment_status/" . $bani_txn_ref . "/";

			$bani_sub_url = $bani_txn_type === 'crypto' ? $cryptoUrl : '/partner/collection/pay_status_check/';
			$bani_env_url = $this->testmode ? 'stage' : 'live';
			$bani_url = 'https://' . $bani_env_url . '.getbani.com/api/v1' . $bani_sub_url;

			$headers = array(
				'MERCHANT-PUB-KEY' =>  $this->public_key,
			);

			$argsFiat = array(
				'headers' => $headers,
				'body'        => array(
					'pay_ref' => $bani_txn_ref,
				),
				'timeout' => 60,
			);
			$args = array(
				'headers' => $headers,
				'timeout' => 60,
			);

			$request = $bani_txn_type === 'crypto' ? wp_remote_get($bani_url, $args) : wp_remote_post($bani_url, $argsFiat);

			$bani_response = json_decode(wp_remote_retrieve_body($request));
			if (!is_wp_error($request) && 200 === wp_remote_retrieve_response_code($request)) {

				$bani_response = json_decode(wp_remote_retrieve_body($request));
				$pay_ext_ref = $bani_txn_type === 'crypto' ?   $bani_response->custom_data->order_ref : $bani_response->data->custom_data->order_ref;
				$pay_status = $bani_txn_type === 'crypto' ?   $bani_response->transaction_status : $bani_response->data->pay_status;

				if ('completed' == $pay_status || 'paid' == $pay_status) {

					$order_details = explode('_', $pay_ext_ref);
					$order_id      = (int) $order_details[0];
					$order         = wc_get_order($order_id);

					// SECURITY: Verify payment integrity before processing
					// This prevents postMessage amount manipulation attacks
					if ( ! $this->verify_payment_integrity( $order_id, $pay_ext_ref ) ) {
						error_log( sprintf(
							'BANI SECURITY ALERT: Payment integrity verification failed. Order ID: %d, Transaction Ref: %s',
							$order_id,
							$bani_txn_ref,
							$pay_ext_ref,
						) );

						
						// Block the payment
						// $order->add_order_note(
						// 	__( 'SECURITY ALERT: Payment blocked due to integrity verification failure. Possible payment amount manipulation detected.', 'bani-payments-for-woocommerce' )
						// );

						$order->add_order_note(
							sprintf(
								__( "SECURITY ALERT: Payment blocked.\nOrder: #%1$d\npay_ref: %2$s\norder_ref: %3$s", 'bani-payments-for-woocommerce' ),
								absint( $order_id ),
								wc_clean( (string) $bani_txn_ref ),
								wc_clean( (string) $pay_ext_ref )
							),
							false
						);

						$order->update_status( 'failed', __( 'Payment integrity verification failed', 'bani-payments-for-woocommerce' ) );

						// Redirect to failure page
						wp_redirect( wc_get_checkout_url() . '?payment_failed=security_check' );
						exit;
					}

					if (in_array($order->get_status(), array('processing', 'completed', 'on-hold', 'paid'))) {

						wp_redirect($this->get_return_url($order));

						exit;
					}

					$order->payment_complete($bani_txn_ref);
					$order->add_order_note(__('Payment via Bani successful (Transaction Reference: ', 'bani-payments-for-woocommerce')
						. sprintf('%s)', $bani_txn_ref));

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

					WC()->cart->empty_cart();
				} else {


					$order_details = explode('_', $pay_ext_ref);
					$order_id      = (int) $order_details[0];
					$order         = wc_get_order($order_id);
					$order->add_order_note(__('Payment via Bani pending (Transaction Reference: ', 'bani-payments-for-woocommerce')
						. sprintf('%s)', $bani_txn_ref));
					$order->update_status('on-hold', '');
				}
			}

			wp_redirect($this->get_return_url($order));


			exit;
		}

		wp_redirect(wc_get_page_permalink('cart'));


		exit;
	}
	/**
	 * Checks if WC version is less than passed in version.
	 *
	 * @param string $version Version to check against.
	 *
	 * @return bool
	 */
	public function is_wc_lt($version)
	{
		return version_compare(WC_VERSION, $version, '<');
	}

	/**
	 * Checks if autocomplete order is enabled for the payment method.
	 *
	 * @since 5.7
	 * @param WC_Order $order Order object.
	 * @return bool
	 */
	protected function is_autocomplete_order_enabled($order)
	{
		$autocomplete_order = false;

		$payment_method = $order->get_payment_method();

		$paystack_settings = get_option('woocommerce_' . $payment_method . '_settings');

		if (isset($paystack_settings['autocomplete_order']) && 'yes' === $paystack_settings['autocomplete_order']) {
			$autocomplete_order = true;
		}

		return $autocomplete_order;
	}


	/**
	 * Change payment complete order status to completed for bani orders.
	 *
	 * @since  3.1.0
	 * @param  string         $status Current order status.
	 * @param  int            $order_id Order ID.
	 * @param  WC_Order|false $order Order object.
	 * @return string
	 */
	public function change_payment_complete_order_status($status, $order_id = 0, $order = false)
	{
		if ($order && 'bani' === $order->get_payment_method()) {
			$status = 'completed';
		}
		return $status;
	}

	/**
	 * Verify Bani widget file integrity to prevent malicious file tampering.
	 *
	 * This function checks if app.min.js has been modified by comparing its hash
	 * against the expected hash. This prevents attackers from injecting malicious
	 * URLs into the payment widget.
	 *
	 * @since 1.0.9
	 * @return bool True if file is intact, false if tampered.
	 */
	private function verify_bani_widget_integrity()
	{
		$widget_file_path = plugin_dir_path( WC_BANI_MAIN_FILE ) . 'assets/js/app.min.js';

		// Check if file exists
		if ( ! file_exists( $widget_file_path ) ) {
			error_log( 'BANI SECURITY ALERT: app.min.js file not found at expected location.' );
			return false;
		}

		// Calculate current file hash
		$current_hash = hash_file( 'sha256', $widget_file_path );

		// Expected hash of the legitimate app.min.js file
		// This is the SHA-256 hash of the original, unmodified file
		// IMPORTANT: Update this hash whenever you legitimately update app.min.js
		$expected_hash = $this->get_expected_widget_hash();

		// Compare hashes
		if ( $current_hash !== $expected_hash ) {
			// Additional check: Scan file content for suspicious URLs
			$file_content = file_get_contents( $widget_file_path );

			// Check if legitimate Bani URLs are present
			$has_legit_stage_url = strpos( $file_content, 'https://stage-checkout.getbani.com/' ) !== false;
			$has_legit_live_url = strpos( $file_content, 'https://live-checkout.getbani.com/' ) !== false;

			// Check for suspicious patterns (common malicious URLs)
			$suspicious_patterns = array(
				'http://',  // Should only use HTTPS
				'checkout.getbani.com', // Without https:// prefix is suspicious
				'.tk/',     // Suspicious TLD
				'.ml/',     // Suspicious TLD
				'.ga/',     // Suspicious TLD
				'.cf/',     // Suspicious TLD
			);

			$has_suspicious_content = false;
			foreach ( $suspicious_patterns as $pattern ) {
				if ( stripos( $file_content, $pattern ) !== false && $pattern !== 'https://' ) {
					$has_suspicious_content = true;
					error_log( 'BANI SECURITY ALERT: Suspicious pattern detected in app.min.js: ' . $pattern );
					break;
				}
			}

			// If file hash doesn't match BUT legitimate URLs are present and no suspicious content,
			// it might be a legitimate update. Store new hash for comparison.
			if ( $has_legit_stage_url && $has_legit_live_url && ! $has_suspicious_content ) {
				// Log for review but don't block (might be legitimate update)
				error_log( 'BANI NOTICE: app.min.js hash mismatch detected. Current hash: ' . $current_hash . '. This might be a legitimate update. Please verify and update the expected hash if needed.' );

				// Store hash mismatch for admin review
				update_option( 'bani_widget_hash_mismatch', array(
					'detected_at' => current_time( 'mysql' ),
					'current_hash' => $current_hash,
					'expected_hash' => $expected_hash,
				) );

				// Allow payment to proceed but flag for review
				return true;
			}

			// File has been tampered with
			return false;
		}

		// File integrity verified
		return true;
	}

	/**
	 * Get expected hash for app.min.js widget file.
	 *
	 * @since 1.0.9
	 * @return string Expected SHA-256 hash.
	 */
	private function get_expected_widget_hash()
	{
		// Calculate and return the hash of the current legitimate file
		// This should be updated whenever you legitimately update app.min.js

		// For initial deployment, calculate the hash of the current file
		// In production, this should be a hardcoded hash value
		$widget_file_path = plugin_dir_path( WC_BANI_MAIN_FILE ) . 'assets/js/app.min.js';

		// Check if we have a stored hash from a previous verification
		$stored_hash = get_option( 'bani_widget_verified_hash', '' );

		if ( empty( $stored_hash ) && file_exists( $widget_file_path ) ) {
			// First time setup - calculate and store the current file hash
			$stored_hash = hash_file( 'sha256', $widget_file_path );
			update_option( 'bani_widget_verified_hash', $stored_hash );
			error_log( 'BANI NOTICE: Initial widget hash calculated and stored: ' . $stored_hash );
		}

		return $stored_hash;
	}

	/**
	 * Send security alert to site administrator.
	 *
	 * @since 1.0.9
	 * @param string $subject Alert subject.
	 * @param string $message Alert message.
	 */
	private function send_security_alert_to_admin( $subject, $message )
	{
		// Check if we've already sent an alert in the last 24 hours to avoid spam
		$last_alert_time = get_option( 'bani_last_security_alert_time', 0 );
		$current_time = current_time( 'timestamp' );

		if ( $current_time - $last_alert_time < 86400 ) { // 24 hours
			return; // Don't send duplicate alerts
		}

		// Get admin email
		$admin_email = get_option( 'admin_email' );

		// Compose email
		$email_subject = '[SECURITY ALERT] ' . $subject . ' - ' . get_bloginfo( 'name' );
		$email_message = "SECURITY ALERT\n\n";
		$email_message .= "Site: " . get_bloginfo( 'name' ) . "\n";
		$email_message .= "URL: " . get_site_url() . "\n\n";
		$email_message .= "Issue: " . $subject . "\n\n";
		$email_message .= "Details: " . $message . "\n\n";
		$email_message .= "Action Required:\n";
		$email_message .= "1. Immediately check your server files for unauthorized modifications\n";
		$email_message .= "2. Verify the integrity of: wp-content/plugins/bani-payments-for-woocommerce/assets/js/app.min.js\n";
		$email_message .= "3. Compare the file with the original from the plugin repository\n";
		$email_message .= "4. If the file has been tampered with, restore it from a clean backup\n";
		$email_message .= "5. Change all FTP, SFTP, and WordPress admin passwords\n";
		$email_message .= "6. Scan your server for malware and backdoors\n\n";
		$email_message .= "Timestamp: " . current_time( 'mysql' ) . "\n";

		// Send email
		wp_mail( $admin_email, $email_subject, $email_message );

		// Update last alert time
		update_option( 'bani_last_security_alert_time', $current_time );

		// Store alert in database for admin review
		$alerts = get_option( 'bani_security_alerts', array() );
		$alerts[] = array(
			'subject' => $subject,
			'message' => $message,
			'timestamp' => current_time( 'mysql' ),
		);

		// Keep only last 50 alerts
		if ( count( $alerts ) > 50 ) {
			$alerts = array_slice( $alerts, -50 );
		}

		update_option( 'bani_security_alerts', $alerts );
	}

	/**
	 * Handle AJAX request from client-side security violation detection.
	 *
	 * @since 1.0.9
	 */
	public function handle_security_violation_report()
	{
		// Security check - verify this is a legitimate request
		// Note: We're allowing nopriv access because this is a security alert that should work even for non-logged in users

		$blocked_url = isset( $_POST['blocked_url'] ) ? sanitize_text_field( $_POST['blocked_url'] ) : 'Unknown';
		$expected_urls = isset( $_POST['expected_urls'] ) ? sanitize_text_field( $_POST['expected_urls'] ) : 'Unknown';
		$user_ip = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( $_SERVER['REMOTE_ADDR'] ) : 'Unknown';
		$user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( $_SERVER['HTTP_USER_AGENT'] ) : 'Unknown';

		// Log the security violation
		error_log( sprintf(
			'BANI CLIENT-SIDE SECURITY ALERT: Malicious URL redirect blocked. Blocked URL: %s | Expected URLs: %s | IP: %s | User Agent: %s',
			$blocked_url,
			$expected_urls,
			$user_ip,
			$user_agent
		) );

		// Send email alert to admin
		$this->send_security_alert_to_admin(
			'Client-Side URL Redirect Blocked',
			sprintf(
				"A malicious payment redirect was detected and blocked on the client-side.\n\n" .
				"Blocked URL: %s\n" .
				"Expected URLs: %s\n" .
				"User IP: %s\n" .
				"User Agent: %s\n\n" .
				"This indicates that the app.min.js file has been tampered with and is attempting to redirect payments to a malicious site.\n\n" .
				"IMMEDIATE ACTION REQUIRED: Restore app.min.js from a clean backup and investigate the security breach.",
				$blocked_url,
				$expected_urls,
				$user_ip,
				$user_agent
			)
		);

		// Store violation in database for forensic analysis
		$violations = get_option( 'bani_url_violation_log', array() );
		$violations[] = array(
			'blocked_url' => $blocked_url,
			'expected_urls' => $expected_urls,
			'ip_address' => $user_ip,
			'user_agent' => $user_agent,
			'timestamp' => current_time( 'mysql' ),
		);

		// Keep only last 100 violations
		if ( count( $violations ) > 100 ) {
			$violations = array_slice( $violations, -100 );
		}

		update_option( 'bani_url_violation_log', $violations );

		wp_send_json_success( array(
			'message' => 'Security violation reported successfully',
		) );
	}

	/**
	 * Generate cryptographic signature for payment data.
	 *
	 * This signature prevents attackers from manipulating payment amounts
	 * via postMessage injection attacks.
	 *
	 * @since 1.0.9
	 * @param array $payment_data Payment data to sign.
	 * @return string HMAC signature.
	 */
	private function generate_payment_signature( $payment_data )
	{
		// Create canonical string from payment data
		$canonical_string = sprintf(
			'%d|%s|%s|%s|%s',
			$payment_data['order_id'],
			$payment_data['amount'],
			$payment_data['currency'],
			$payment_data['txnref'],
			$payment_data['email']
		);

		// Generate HMAC using secret key derived from WordPress salts
		$secret_key = $this->get_signature_secret_key();
		$signature = hash_hmac( 'sha256', $canonical_string, $secret_key );

		return $signature;
	}

	/**
	 * Get secret key for payment signature generation.
	 *
	 * Uses WordPress AUTH_KEY and SECURE_AUTH_KEY for additional entropy.
	 *
	 * @since 1.0.9
	 * @return string Secret key.
	 */
	private function get_signature_secret_key()
	{
		// Combine WordPress security keys with plugin-specific salt
		$keys = array(
			defined( 'AUTH_KEY' ) ? AUTH_KEY : '',
			defined( 'SECURE_AUTH_KEY' ) ? SECURE_AUTH_KEY : '',
			'bani_payment_signature_v1',
			$this->public_key, // Include merchant's public key for uniqueness
		);

		return hash( 'sha256', implode( '|', $keys ) );
	}

	/**
	 * Verify payment signature and amount before processing.
	 *
	 * This is the critical defense against postMessage manipulation attacks.
	 *
	 * @since 1.0.9
	 * @param int    $order_id Order ID.
	 * @param string $txnref Transaction reference.
	 * @return bool True if verification passes, false otherwise.
	 */
	private function verify_payment_integrity( $order_id, $txnref )
	{
		$order = wc_get_order( $order_id );

		if ( ! $order ) {
			error_log( 'BANI SECURITY ALERT: Payment verification failed - Order not found: ' . $order_id );
			return false;
		}

		// Get stored expected values
		$expected_amount = $order->get_meta( '_bani_expected_amount', true );
		$expected_currency = $order->get_meta( '_bani_expected_currency', true );
		$expected_signature = $order->get_meta( '_bani_payment_signature', true );
		$stored_txnref = $order->get_meta( '_bani_txn_ref', true );

		// Verify transaction reference matches
		if ( $stored_txnref !== $txnref ) {
			error_log( sprintf(
				'BANI SECURITY ALERT: Transaction reference mismatch. Order ID: %d, Expected: %s, Received: %s',
				$order_id,
				$stored_txnref,
				$txnref
			) );
			return false;
		}

		// Verify all expected values are present
		if ( empty( $expected_amount ) || empty( $expected_currency ) || empty( $expected_signature ) ) {
			error_log( 'BANI SECURITY ALERT: Missing expected payment data for order: ' . $order_id );
			return false;
		}

		// Regenerate signature to verify integrity
		$email = method_exists( $order, 'get_billing_email' ) ? $order->get_billing_email() : $order->billing_email;
		$recalculated_signature = $this->generate_payment_signature( array(
			'order_id' => $order_id,
			'amount' => $expected_amount,
			'currency' => $expected_currency,
			'txnref' => $txnref,
			'email' => $email,
		) );

		// Verify signature matches (timing-safe comparison)
		if ( ! hash_equals( $expected_signature, $recalculated_signature ) ) {
			error_log( 'BANI SECURITY ALERT: Payment signature verification failed for order: ' . $order_id );
			$this->send_security_alert_to_admin(
				'Payment Signature Mismatch',
				sprintf(
					"Payment signature verification failed for Order #%d.\n\n" .
					"This could indicate a postMessage manipulation attack.\n\n" .
					"Transaction Reference: %s\n\n" .
					"The payment has been blocked.",
					$order_id,
					$txnref
				)
			);
			return false;
		}

		return true;
	}

	/**
	 * Handle AJAX request from client-side amount tampering detection.
	 *
	 * @since 1.0.9
	 */
	public function handle_amount_tampering_report()
	{
		$expected_amount = isset( $_POST['expected_amount'] ) ? sanitize_text_field( $_POST['expected_amount'] ) : 'Unknown';
		$received_amount = isset( $_POST['received_amount'] ) ? sanitize_text_field( $_POST['received_amount'] ) : 'Unknown';
		$order_id = isset( $_POST['order_id'] ) ? absint( $_POST['order_id'] ) : 0;
		$signature = isset( $_POST['signature'] ) ? sanitize_text_field( $_POST['signature'] ) : '';
		$user_ip = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( $_SERVER['REMOTE_ADDR'] ) : 'Unknown';
		$user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( $_SERVER['HTTP_USER_AGENT'] ) : 'Unknown';

		// Log the security violation
		error_log( sprintf(
			'BANI CRITICAL SECURITY ALERT: Payment amount tampering detected! Order ID: %d | Expected: %s | Received: %s | IP: %s',
			$order_id,
			$expected_amount,
			$received_amount,
			$user_ip
		) );

		// Send immediate email alert to admin
		$this->send_security_alert_to_admin(
			'CRITICAL: Payment Amount Tampering Detected',
			sprintf(
				"CRITICAL SECURITY INCIDENT\n\n" .
				"Payment amount tampering was detected and blocked on the client-side.\n\n" .
				"Order ID: %d\n" .
				"Expected Amount: %s\n" .
				"Tampered Amount: %s\n" .
				"Difference: %s\n" .
				"User IP: %s\n" .
				"User Agent: %s\n" .
				"Payment Signature: %s\n\n" .
				"This indicates a postMessage manipulation attack was attempted.\n\n" .
				"IMMEDIATE ACTIONS REQUIRED:\n" .
				"1. Review server access logs for suspicious activity\n" .
				"2. Check for XSS vulnerabilities or compromised JavaScript\n" .
				"3. Scan for malware and browser extensions\n" .
				"4. Review firewall logs for the IP address: %s\n" .
				"5. The payment has been automatically blocked\n\n" .
				"Timestamp: %s",
				$order_id,
				number_format( floatval( $expected_amount ) / 100, 2 ),
				number_format( floatval( $received_amount ) / 100, 2 ),
				number_format( abs( floatval( $expected_amount ) - floatval( $received_amount ) ) / 100, 2 ),
				$user_ip,
				$user_agent,
				$signature,
				$user_ip,
				current_time( 'mysql' )
			)
		);

		// Store tampering attempt in database for forensic analysis
		$tampering_log = get_option( 'bani_amount_tampering_log', array() );
		$tampering_log[] = array(
			'order_id' => $order_id,
			'expected_amount' => $expected_amount,
			'received_amount' => $received_amount,
			'difference' => abs( floatval( $expected_amount ) - floatval( $received_amount ) ),
			'signature' => $signature,
			'ip_address' => $user_ip,
			'user_agent' => $user_agent,
			'timestamp' => current_time( 'mysql' ),
		);

		// Keep only last 100 tampering attempts
		if ( count( $tampering_log ) > 100 ) {
			$tampering_log = array_slice( $tampering_log, -100 );
		}

		update_option( 'bani_amount_tampering_log', $tampering_log );

		// If order exists, add security note
		if ( $order_id > 0 ) {
			$order = wc_get_order( $order_id );
			if ( $order ) {
				$order->add_order_note(
					sprintf(
						__( 'SECURITY ALERT: Payment amount tampering attempt detected and blocked. Expected: %s, Attempted: %s', 'bani-payments-for-woocommerce' ),
						number_format( floatval( $expected_amount ) / 100, 2 ),
						number_format( floatval( $received_amount ) / 100, 2 )
					)
				);
			}
		}

		wp_send_json_success( array(
			'message' => 'Amount tampering reported and blocked successfully',
		) );
	}
}
