<?php

namespace DigitalApps\PaymentsForAdyen\Gateways;

use WC_Payment_Gateway;
use \DigitalApps\PaymentsForAdyen\Adyen_Client;

defined('ABSPATH') || exit;

/**
 * Adyen Card Gateway
 */
class Adyen_Card_Gateway extends WC_Payment_Gateway
{
	// Adyen payment method type constants
	const ADYEN_METHOD_TYPE = 'scheme';

	// Adyen result code constants
	const RESULT_AUTHORISED = 'Authorised';
	const RESULT_REFUSED = 'Refused';
	const RESULT_REDIRECT_SHOPPER = 'RedirectShopper';
	const RESULT_ERROR = 'Error';

	// Capture mode constants
	const CAPTURE_MODE_AUTOMATIC = 'automatic';
	const CAPTURE_MODE_MANUAL = 'manual';

	// Cached settings
	private $digitalapps_payments_for_adyen_settings = null;

	/** @var \DigitalApps\PaymentsForAdyen\Logger */
	private $logger;

	public function __construct()
	{
		$this->logger = new \DigitalApps\PaymentsForAdyen\Logger();
		$this->id                 = 'digitalapps_payments_for_adyen_card';
		$this->method_title       = __('Adyen Card', 'digital-apps-payments-for-adyen');
		$this->method_description = __('Accept card payments via Adyen.', 'digital-apps-payments-for-adyen');
		$this->has_fields         = true;

		// Define supported features
		$this->supports = [
			'products',
			'refunds', // Add refund support
		];

		// Initialize properties
		$this->init_form_fields();
		$this->init_settings();

		$this->enabled = $this->get_option('enabled');
		$this->title   = $this->get_option('title');

		// Auto-enable gateway if credentials are present and gateway is not explicitly disabled
		$this->maybe_auto_enable_gateway();

		add_action('woocommerce_update_options_payment_gateways_' . $this->id, [$this, 'process_admin_options']);
		// Change hook to admin_notices for only WooCommerce settings page
		add_action('admin_notices', [$this, 'check_adyen_status']);

		// Add WooCommerce Blocks support
		add_action('woocommerce_rest_checkout_process_payment_with_context', [$this, 'process_payment_with_context'], 10, 2);
		if (defined('WP_DEBUG') && WP_DEBUG) {
			$this->logger->log('DEBUG', ['message' => '[Digital Apps Adyen] Registered woocommerce_rest_checkout_process_payment_with_context hook for ' . $this->id]);
		}

		// Note: AJAX handlers are registered in Adyen_Plugin::init_hooks() to ensure they're available early enough

		// Enqueue payment scripts
		add_action('wp_enqueue_scripts', [$this, 'enqueue_payment_scripts']);
	}

	/**
	 * Get cached Adyen settings from WordPress options
	 * 
	 * Retrieves Adyen configuration settings and caches them in a class property
	 * to avoid repeated database calls within the same request.
	 * 
	 * @return array Associative array of Adyen settings (apiKey, merchantAccount, clientKey, testMode, captureMode)
	 */
	private function get_adyen_settings()
	{
		if ($this->digitalapps_payments_for_adyen_settings === null) {
			$this->digitalapps_payments_for_adyen_settings = get_option('digitalapps_payments_for_adyen_settings', []);
		}
		return $this->digitalapps_payments_for_adyen_settings;
	}

	/**
	 * Enqueue the locally bundled Adyen Web checkout script.
	 * 
	 * Passes public checkout configuration to JavaScript via wp_localize_script().
	 * Only loads on checkout pages to optimize performance.
	 * 
	 * @return void
	 */
	public function enqueue_payment_scripts()
	{
		if (!is_checkout()) {
			return;
		}

		$settings = $this->get_adyen_settings();
		$environment = !empty($settings['testMode']) ? 'test' : 'live';
		$client_key = $settings['clientKey'] ?? '';
		$base_location = wc_get_base_location();
		$country_code = $base_location['country'] ?? 'US';
		$locale = str_replace('_', '-', determine_locale());

		// Check if we're using blocks checkout
		$is_blocks = function_exists('has_block') && has_block('woocommerce/checkout');

		if ($is_blocks) {
			if (defined('WP_DEBUG') && WP_DEBUG) {
				$this->logger->log('DEBUG', ['message' => '[Digital Apps Adyen] Blocks checkout detected']);
			}
		} else {
			// For classic checkout, enqueue initialization script
			wp_enqueue_script(
				'digitalapps-payments-for-adyen-card-init',
				DIGITALAPPS_PAYMENTS_FOR_ADYEN_URL . 'build/checkout/digitalapps-payments-for-adyen-card-init.js',
				['jquery'],
				DIGITALAPPS_PAYMENTS_FOR_ADYEN_VERSION,
				true
			);

			// Pass data to JavaScript
			wp_localize_script('digitalapps-payments-for-adyen-card-init', 'digitalAppsPaymentsForAdyenConfig', [
				'environment' => $environment,
				'clientKey' => $client_key,
				'countryCode' => $country_code,
				'locale' => $locale,
				'messages' => [
					'missingConfig' => __('The card payment form is not configured. Please contact the site administrator.', 'digital-apps-payments-for-adyen'),
					'loadFailed' => __('The card payment form could not be loaded. Please refresh the page and try again.', 'digital-apps-payments-for-adyen'),
				],
			]);
		}
	}

	/**
	 * Validate if required Adyen credentials are configured
	 * 
	 * Checks if the necessary Adyen API credentials are present in settings.
	 * Optionally validates client key presence based on parameter.
	 * 
	 * @param bool $require_client_key Whether to require client key validation (default: false).
	 *                                 When true, validates apiKey, merchantAccount AND clientKey.
	 *                                 When false, only validates apiKey and merchantAccount.
	 * @return bool True if all required credentials are present, false otherwise
	 */
	private function validate_adyen_credentials($require_client_key = false)
	{
		$settings = $this->get_adyen_settings();

		$has_required = !empty($settings['apiKey']) && !empty($settings['merchantAccount']);

		if ($require_client_key) {
			$has_required = $has_required && !empty($settings['clientKey']);
		}

		return $has_required;
	}

	/**
	 * Auto-enable gateway if credentials are present and gateway is not explicitly disabled
	 * 
	 * Automatically enables the Adyen Card gateway and sets default title/description
	 * when Adyen API credentials are configured and the gateway hasn't been manually
	 * enabled or disabled by the user.
	 * 
	 * @return void
	 */
	private function maybe_auto_enable_gateway()
	{
		// Only auto-enable if not already configured
		if ($this->enabled !== '' && $this->enabled !== null) {
			return; // User has already made a choice
		}

		// Check if Adyen credentials are present
		if ($this->validate_adyen_credentials()) {
			// Auto-enable the gateway
			$gateway_settings = get_option('woocommerce_digitalapps_payments_for_adyen_card_settings', []);
			$gateway_settings['enabled'] = 'yes';
			if (empty($gateway_settings['title'])) {
				$gateway_settings['title'] = __('Credit/Debit Card (Adyen)', 'digital-apps-payments-for-adyen');
			}
			if (empty($gateway_settings['description'])) {
				$gateway_settings['description'] = __('Pay securely with your credit or debit card via Adyen.', 'digital-apps-payments-for-adyen');
			}
			update_option('woocommerce_digitalapps_payments_for_adyen_card_settings', $gateway_settings);
			$this->enabled = 'yes';
		}
	}

	/**
	 * Check if WooCommerce conditions are met for payment gateway availability
	 * 
	 * Validates that WooCommerce is active and the environment is suitable for
	 * displaying the payment gateway. Always returns true on frontend to let
	 * WooCommerce handle context-specific availability checks.
	 * 
	 * @return bool True if WooCommerce is available, false otherwise
	 */
	private function is_woocommerce_available()
	{
		// Check if WooCommerce is active
		if (!class_exists('WooCommerce')) {
			if (defined('WP_DEBUG') && WP_DEBUG) {
				$this->logger->log('DEBUG', ['message' => '[Digital Apps Adyen] is_woocommerce_available: WooCommerce not active']);
			}
			return false;
		}

		// For frontend, always return true - let WooCommerce handle the context
		// The cart empty check should not prevent gateway from being available
		if (!is_admin()) {
			return true;
		}

		return true;
	}

	public function init_form_fields()
	{
		$this->form_fields = [
			'enabled' => [
				'title'   => __('Enable/Disable', 'digital-apps-payments-for-adyen'),
				'type'    => 'checkbox',
				'label'   => __('Enable Adyen Card', 'digital-apps-payments-for-adyen'),
				'default' => 'no',
			],
			'title' => [
				'title'       => __('Title', 'digital-apps-payments-for-adyen'),
				'type'        => 'text',
				'description' => __('This controls the title seen during checkout.', 'digital-apps-payments-for-adyen'),
				'default'     => __('Credit/Debit Card (Adyen)', 'digital-apps-payments-for-adyen'),
				'desc_tip'    => true,
			],
		];

		// Add status information to form fields only in admin context
		if (is_admin() && function_exists('wp_remote_post')) {
			try {
				$this->form_fields = Adyen_Gateway_Utils::add_status_to_form_fields($this->form_fields, $this->id);
			} catch (\Exception $e) {
				// Silently fail if status check fails - gateway should still work
			}
		}
	}

	private function check_method_status()
	{
		$client = new Adyen_Client();
		$methods = $client->get_payment_methods();

		foreach ($methods as $method) {
			if ($method['type'] === 'scheme') {
				return true;
			}
		}
		return false;
	}

	public function is_available()
	{
		if (defined('WP_DEBUG') && WP_DEBUG) {
			$this->logger->log('DEBUG', ['message' => '[Digital Apps Adyen] is_available() called for digitalapps_payments_for_adyen_card. enabled=' . $this->enabled . ' is_admin=' . (is_admin() ? '1' : '0')]);
		}

		// First call parent is_available() to ensure WooCommerce base conditions are met
		$parent_available = parent::is_available();
		if (!$parent_available) {
			if (defined('WP_DEBUG') && WP_DEBUG) {
				$this->logger->log('DEBUG', ['message' => '[Digital Apps Adyen] is_available: parent::is_available() returned false']);
			}
			return false;
		}

		// Check if gateway is enabled
		if ('yes' !== $this->enabled) {
			if (defined('WP_DEBUG') && WP_DEBUG) {
				$this->logger->log('DEBUG', ['message' => '[Digital Apps Adyen] is_available: gateway disabled (enabled=' . $this->enabled . ')']);
			}
			return false;
		}

		// Check if credentials are configured first
		$settings = get_option('digitalapps_payments_for_adyen_settings', []);
		if (defined('WP_DEBUG') && WP_DEBUG) {
			$hasApi = empty($settings['apiKey']) ? '0' : '1';
			$hasMa = empty($settings['merchantAccount']) ? '0' : '1';
			$this->logger->log('DEBUG', ['message' => '[Digital Apps Adyen] is_available: settings present apiKey=' . $hasApi . ' merchantAccount=' . $hasMa]);
		}

		// Only require API Key and Merchant Account for availability. Client Key is needed only to render card fields.
		if (empty($settings['apiKey']) || empty($settings['merchantAccount'])) {
			if (defined('WP_DEBUG') && WP_DEBUG) {
				$this->logger->log('ERROR', ['message' => '[Digital Apps Adyen] is_available: missing apiKey or merchantAccount']);
			}
			return false;
		}

		// For frontend checkout, don't make API calls on every page load
		// Instead, assume the gateway is available if credentials are present
		// The actual payment method validation will happen during payment processing
		if (!is_admin()) {
			if (defined('WP_DEBUG') && WP_DEBUG) {
				$this->logger->log('DEBUG', ['message' => '[Digital Apps Adyen] is_available: returning true on frontend']);
			}
			return true;
		}

		// Only check with Adyen API in admin context (for status display)
		try {
			$client = new Adyen_Client();
			$methods = $client->get_payment_methods();

			foreach ($methods as $method) {
				if ($method['type'] === 'scheme') {
					return true;
				}
			}
		} catch (\Exception $e) {
			// If API call fails, still allow the gateway to be available
			// The error will be handled during actual payment processing
			return true;
		}

		return false;
	}

	/**
	 * Render payment fields at checkout using Adyen Drop-in
	 */
	public function payment_fields()
	{
		// Display description if set
		if ($this->description) {
			echo '<p>' . wp_kses_post($this->description) . '</p>';
		}

		// Check if client key is available
		if (!$this->validate_adyen_credentials(true)) {
			if (current_user_can('manage_woocommerce')) {
				echo '<p style="color: #a00;">Adyen configuration incomplete: Client Key is missing.</p>';
			} else {
				echo '<p>Card payment form is temporarily unavailable.</p>';
			}
			return;
		}

		// Render the Adyen Card Component container.
		echo '<div id="digitalapps-payments-for-adyen-card-component" class="digitalAppsAdyenCard"></div>';
		echo '<input type="hidden" id="digitalapps-payments-for-adyen-card-state" name="digitalapps_payments_for_adyen_card_state" value="" />';

		// Scripts are now loaded via wp_enqueue_scripts hook
	}

	public function check_adyen_status()
	{
		// Only show on WooCommerce settings pages
		$screen = get_current_screen();
		if (!$screen || $screen->id !== 'woocommerce_page_wc-settings') {
			return;
		}

		// Check if credentials are missing
		$settings = get_option('digitalapps_payments_for_adyen_settings', []);
		$missing_credentials = empty($settings['apiKey']) || empty($settings['merchantAccount']) || empty($settings['clientKey']);

		if ('yes' === $this->enabled && $missing_credentials) {
			echo '<div class="notice notice-error"><p>';
			echo '<strong>⚠️ Adyen Card Payment Method Issue:</strong> ';
			echo 'The Adyen Card gateway is enabled but <strong>API credentials are missing</strong>. ';
			echo 'Customers will see "No payment methods available" at checkout. ';
			echo '<br><strong>Action Required:</strong> Configure your Adyen API Key, Merchant Account, and Client Key in the Adyen settings.';
			echo '</p></div>';
			return;
		}

		// If credentials exist but gateway still not available, show API connectivity issue
		if ('yes' === $this->enabled && !$missing_credentials && !parent::is_available()) {
			echo '<div class="notice notice-warning"><p>';
			echo '<strong>⚠️ Adyen Card Payment Method Issue:</strong> ';
			echo 'API credentials are configured but the payment method is not available. ';
			echo 'This could be due to invalid credentials or the payment method not being enabled in your Adyen Customer Area. ';
			echo '<br><strong>Action Required:</strong> Verify your API credentials and ensure Card payments are enabled in your Adyen account.';
			echo '</p></div>';
			return;
		}

		// Specific notice when Client Key is missing
		if ('yes' === $this->enabled && !$missing_credentials && empty($settings['clientKey'])) {
			echo '<div class="notice notice-info"><p>';
			echo '<strong>ℹ️ Adyen Card Notice:</strong> Client Key is not configured. The gateway can be available, but the on-page card form cannot render until a Client Key is added in Adyen settings.';
			echo '</p></div>';
			// Do not return; informational only
		}

		// Show enhanced status if everything is working
		Adyen_Gateway_Utils::display_enhanced_adyen_status_notice($this, true);
	}

	public function process_payment($order_id)
	{
		$order = \wc_get_order($order_id);
		if (!$order) {
			\wc_add_notice(__('Payment processing failed. Please try again.', 'digital-apps-payments-for-adyen'), 'error');
			return ['result' => 'fail'];
		}

		// Get the card payment state from the Adyen component
		// Use wp_unslash() instead of sanitize_text_field() to preserve JSON structure
		// WooCommerce verifies its checkout nonce before invoking gateway process_payment().
		// phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- JSON is decoded and recursively sanitized below.
		$card_state = isset($_POST['digitalapps_payments_for_adyen_card_state']) ? wp_unslash($_POST['digitalapps_payments_for_adyen_card_state']) : '';

		if (empty(trim($card_state))) {
			\wc_add_notice(__('Payment data is missing. Please try again.', 'digital-apps-payments-for-adyen'), 'error');
			return ['result' => 'fail'];
		}

		// Decode the payment state
		$payment_state = \json_decode($card_state, true);
		if (!$payment_state || !isset($payment_state['paymentMethod'])) {
			\wc_add_notice(__('Invalid payment data. Please try again.', 'digital-apps-payments-for-adyen'), 'error');
			return ['result' => 'fail'];
		}
		$payment_state['paymentMethod'] = map_deep($payment_state['paymentMethod'], 'sanitize_text_field');

		$session_manager = new \DigitalApps\PaymentsForAdyen\Adyen_Session_Manager();
		$session_key = $session_manager->create_session($order->get_id());
		if (!$session_key) {
			\wc_add_notice(__('Payment processing failed. Please try again.', 'digital-apps-payments-for-adyen'), 'error');
			return ['result' => 'fail'];
		}

		$client = new Adyen_Client();
		$payment_data = [
			'paymentMethod' => $payment_state['paymentMethod'],
			'returnUrl' => $session_manager::action_url($session_key),
		];
		if (isset($payment_state['browserInfo']) && is_array($payment_state['browserInfo'])) {
			$payment_data['browserInfo'] = $this->sanitize_browser_info($payment_state['browserInfo']);
		}

		$response = $client->create_payment($order, $payment_data);
		$classification = \DigitalApps\PaymentsForAdyen\Adyen_Result::classify($response);
		$settings = get_option('digitalapps_payments_for_adyen_settings', []);
		$capture_mode = 'manual' === ($settings['captureMode'] ?? '') ? 'manual' : 'automatic';
		\DigitalApps\PaymentsForAdyen\Adyen_Result::apply_to_order($order, is_array($response) ? $response : [], $capture_mode);

		if (\DigitalApps\PaymentsForAdyen\Adyen_Result::ACTION === $classification) {
			$updated = $session_manager->update_session($session_key, [
				'payment_data' => $response['paymentData'] ?? '',
				'action' => $response['action'],
			]);
			if ($updated) {
				return [
					'result' => 'success',
					'redirect' => $session_manager::action_url($session_key),
				];
			}
		}

		$session_manager->delete_session($session_key);
		if (in_array($classification, [
			\DigitalApps\PaymentsForAdyen\Adyen_Result::AUTHORISED,
			\DigitalApps\PaymentsForAdyen\Adyen_Result::PENDING,
		], true)) {
			return [
				'result' => 'success',
				'redirect' => $this->get_return_url($order),
			];
		}

		\wc_add_notice(\DigitalApps\PaymentsForAdyen\Adyen_Result::shopper_message($classification), 'error');
		return ['result' => 'fail'];
	}

	/**
	 * Process a refund through Adyen API
	 * 
	 * Validates the order, amount, and PSP reference, then sends a refund request
	 * to Adyen. Supports both full and partial refunds.
	 *
	 * @param int $order_id WooCommerce order ID to refund
	 * @param float|null $amount Refund amount (must be > 0 and <= order total)
	 * @param string $reason Optional refund reason for record keeping
	 * @return bool|\WP_Error True on success, WP_Error on failure
	 */
	public function process_refund($order_id, $amount = null, $reason = '')
	{
		$order = \wc_get_order($order_id);
		if (!$order) {
			if (defined('WP_DEBUG') && WP_DEBUG) {
				$this->logger->log('ERROR', ['message' => '[Digital Apps Adyen] Refund failed: Order not found for ID ' . $order_id]);
			}
			return false;
		}

		$pspReference = $order->get_transaction_id();
		if (empty($pspReference)) {
			$order->add_order_note(__('Adyen Refund Failed: No Adyen PSP Reference found for this order.', 'digital-apps-payments-for-adyen'));
			if (defined('WP_DEBUG') && WP_DEBUG) {
				$this->logger->log('ERROR', ['message' => '[Digital Apps Adyen] Refund failed for Order ID ' . $order_id . ': No PSP Reference found.']);
			}
			return new \WP_Error('digitalapps_payments_for_adyen_refund_error', __('Adyen Refund Failed: No Adyen PSP Reference found for this order.', 'digital-apps-payments-for-adyen'));
		}

		$remaining_refundable = $this->get_available_refund_amount($order, $amount);
		// Ensure cumulative refunds cannot exceed the captured order total.
		if (is_null($amount) || $amount <= 0 || (float) $amount > $remaining_refundable) {
			/* translators: %s: Invalid refund amount. */
			$order->add_order_note(sprintf(__('Adyen Refund Failed: Invalid refund amount %s.', 'digital-apps-payments-for-adyen'), $amount));
			if (defined('WP_DEBUG') && WP_DEBUG) {
				$this->logger->log('ERROR', ['message' => '[Digital Apps Adyen] Refund failed for Order ID ' . $order_id . ': Invalid refund amount ' . $amount]);
			}
			/* translators: %s: Invalid refund amount. */
			return new \WP_Error('digitalapps_payments_for_adyen_refund_error', sprintf(__('Adyen Refund Failed: Invalid refund amount %s.', 'digital-apps-payments-for-adyen'), $amount));
		}

		$currency = $order->get_currency();
		$refund_sequence = count($order->get_refunds()) + 1;
		$minor_amount = \DigitalApps\PaymentsForAdyen\Adyen_Amount::to_minor_units($amount, $currency);
		$operation_id = 'refund:' . $refund_sequence . ':' . $minor_amount;
		$existing_operation = \DigitalApps\PaymentsForAdyen\Adyen_Operation::get($order, $operation_id);
		if (in_array($existing_operation['status'] ?? '', ['initiated', 'succeeded'], true)) {
			return true;
		}
		$idempotency_key = \DigitalApps\PaymentsForAdyen\Adyen_Operation::key_for_order($order, $operation_id);
		$client = Adyen_Client::for_order($order);
		$response = $client->refund($pspReference, $amount, $currency, $reason, $idempotency_key);

		if (isset($response['status']) && $response['status'] === 'error') {
			$error_message = $response['message'] ?? __('Unknown Adyen API error during refund.', 'digital-apps-payments-for-adyen');
			/* translators: %s: Refund failure message. */
			$order->add_order_note(sprintf(__('Adyen Refund Failed: %s', 'digital-apps-payments-for-adyen'), $error_message));
			if (defined('WP_DEBUG') && WP_DEBUG) {
				$this->logger->log('ERROR', ['message' => '[Digital Apps Adyen] Refund failed for Order ID ' . $order_id . ': ' . $error_message]);
			}
			/* translators: %s: Refund failure message. */
			return new \WP_Error('digitalapps_payments_for_adyen_refund_error', sprintf(__('Adyen Refund Failed: %s', 'digital-apps-payments-for-adyen'), $error_message));
		}

		if (isset($response['status']) && $response['status'] === 'received') {
			\DigitalApps\PaymentsForAdyen\Adyen_Operation::mark($order, $operation_id, 'initiated', [
				'type' => 'refund',
				'pspReference' => sanitize_text_field($response['pspReference'] ?? ''),
				'originalReference' => $pspReference,
				'amountValue' => $minor_amount,
				'currency' => $currency,
				'preRefundStatus' => $order->get_status(),
			]);
			/* translators: 1: Refund amount, 2: Currency, 3: Adyen PSP reference, 4: Refund status. */
			$order->add_order_note(sprintf(__('Adyen Refund initiated for %1$s %2$s. PSP Reference: %3$s. Status: %4$s', 'digital-apps-payments-for-adyen'), $amount, $currency, $response['pspReference'] ?? 'N/A', $response['status']));
			if (defined('WP_DEBUG') && WP_DEBUG) {
				$this->logger->log('DEBUG', ['message' => '[Digital Apps Adyen] Refund initiated for Order ID ' . $order_id . '. PSP Reference: ' . ($response['pspReference'] ?? 'N/A')]);
			}
			return true;
		}

		// Generic failure
		$order->add_order_note(__('Adyen Refund Failed: Unexpected response from Adyen API.', 'digital-apps-payments-for-adyen'));
		if (defined('WP_DEBUG') && WP_DEBUG) {
			$this->logger->log('ERROR', ['message' => 'Refund failed with an unexpected Adyen response', 'response' => $response]);
		}
		return new \WP_Error('digitalapps_payments_for_adyen_refund_error', __('Adyen Refund Failed: Unexpected response from Adyen API.', 'digital-apps-payments-for-adyen'));
	}

	/**
	 * Return the balance available to the refund WooCommerce is currently submitting.
	 *
	 * WooCommerce persists the new WC_Order_Refund before invoking the gateway, so
	 * its amount is already included in get_total_refunded(). Add back only one
	 * fresh, unlinked record that matches this request.
	 */
	private function get_available_refund_amount($order, $amount)
	{
		$remaining = max(0, (float) $order->get_total() - (float) $order->get_total_refunded());
		$operations = $order->get_meta(\DigitalApps\PaymentsForAdyen\Adyen_Operation::META_KEY, true);
		$linked_refund_ids = [];
		foreach ((array) $operations as $operation) {
			if (is_array($operation) && !empty($operation['wooRefundId'])) {
				$linked_refund_ids[] = (int) $operation['wooRefundId'];
			}
		}
		foreach ($order->get_refunds() as $refund) {
			$created = $refund->get_date_created();
			if (
				!in_array((int) $refund->get_id(), $linked_refund_ids, true)
				&& abs((float) $refund->get_amount() - (float) $amount) < 0.000001
				&& $created
				&& $created->getTimestamp() >= time() - MINUTE_IN_SECONDS
			) {
				return $remaining + (float) $refund->get_amount();
			}
		}
		return $remaining;
	}

	/**
	 * Process payment for WooCommerce Blocks
	 * 
	 * This method is called by the woocommerce_rest_checkout_process_payment_with_context hook.
	 * It validates payment data, sends the payment request to Adyen, and handles the response.
	 * @param \Automattic\WooCommerce\StoreApi\Payments\PaymentContext $context Payment context containing order and payment data
	 * @param \Automattic\WooCommerce\StoreApi\Payments\PaymentResult $payment_result Payment result object to update with status and redirect URL
	 * @return void
	 */
	public function process_payment_with_context($context, &$payment_result)
	{
		// Validate payment context
		if (!$this->validate_payment_context($context, $payment_result)) {
			return;
		}

		try {
			$order = $context->order;
			$payment_data = $context->payment_data;

			if (defined('WP_DEBUG') && WP_DEBUG) {
				$this->logger->log('DEBUG', ['message' => '[Digital Apps Adyen] Order ID: ' . $order->get_id()]);
				$this->logger->log('DEBUG', ['message' => '[Digital Apps Adyen] Payment data keys: ' . implode(', ', array_keys($payment_data))]);
			}

			// Extract and validate payment state
			$payment_state = $this->extract_and_validate_payment_state($payment_data, $order, $payment_result);
			if (!$payment_state) {
				return; // Error already set in helper method
			}

			$session_manager = new \DigitalApps\PaymentsForAdyen\Adyen_Session_Manager();
			$session_key = $session_manager->create_session($order->get_id());
			if (!$session_key) {
				$this->create_error_response($payment_result, __('Payment processing failed. Please try again.', 'digital-apps-payments-for-adyen'));
				return;
			}

			// Prepare and send payment request
			$response = $this->prepare_and_send_payment_request(
				$payment_state,
				$order,
				$session_manager::action_url($session_key)
			);

			// Handle the payment response
			$this->handle_payment_response($response, $order, $payment_result, $session_key);
		} catch (\Throwable $e) {
			if (defined('WP_DEBUG') && WP_DEBUG) {
				$this->logger->log('ERROR', ['message' => '[Digital Apps Adyen] Payment processing raised an exception']);
			}

			$this->create_error_response(
				$payment_result,
				__('Payment processing failed. Please try again.', 'digital-apps-payments-for-adyen')
			);
		}
	}

	/**
	 * Validate payment context and ensure this is our payment method
	 * 
	 * Checks if the current payment method matches this gateway's ID before processing.
	 * Returns false if this is not our payment method to allow other gateways to process.
	 *
	 * @param \Automattic\WooCommerce\StoreApi\Payments\PaymentContext $context Payment context object containing payment method ID
	 * @param \Automattic\WooCommerce\StoreApi\Payments\PaymentResult $payment_result Payment result object to update on error
	 * @return bool True if this is our payment method and valid, false otherwise
	 */
	private function validate_payment_context($context, &$payment_result)
	{
		try {
			if (defined('WP_DEBUG') && WP_DEBUG) {
				$this->logger->log('DEBUG', ['message' => '[Digital Apps Adyen] process_payment_with_context called']);
				$this->logger->log('DEBUG', ['message' => '[Digital Apps Adyen] Payment method: ' . $context->payment_method]);
				$this->logger->log('DEBUG', ['message' => '[Digital Apps Adyen] Our ID: ' . $this->id]);
			}

			// Only process if this is our payment method
			if ($context->payment_method !== $this->id) {
				if (defined('WP_DEBUG') && WP_DEBUG) {
					$this->logger->log('DEBUG', ['message' => '[Digital Apps Adyen] Not our payment method, skipping']);
				}
				return false;
			}

			if (defined('WP_DEBUG') && WP_DEBUG) {
				$this->logger->log('DEBUG', ['message' => '[Digital Apps Adyen] Processing Adyen payment...']);
			}
			return true;
		} catch (\Throwable $e) {
			if (defined('WP_DEBUG') && WP_DEBUG) {
				$this->logger->log('ERROR', ['message' => '[Digital Apps Adyen] Payment context validation raised an exception']);
			}

			$this->create_error_response(
				$payment_result,
				__('Payment processing failed. Please try again.', 'digital-apps-payments-for-adyen')
			);
			return false;
		}
	}

	/**
	 * Extract and validate payment state from payment data
	 * 
	 * Extracts the Adyen card state from payment data (supports both associative array
	 * and key/value pairs formats). Validates the JSON structure and rejects missing data
	 * regardless of the site's debug configuration.
	 *
	 * @param array $payment_data Payment data from WooCommerce Blocks checkout (may be associative array or list of key/value pairs)
	 * @param \WC_Order $order The WooCommerce order object
	 * @param \Automattic\WooCommerce\StoreApi\Payments\PaymentResult $payment_result Payment result object to update on error
	 * @return array|null Decoded payment state array containing paymentMethod data, or null if invalid/missing
	 */
	private function extract_and_validate_payment_state($payment_data, $order, &$payment_result)
	{
		// Extract card state using helper method
		$card_state = $this->extract_card_state_from_payment_data($payment_data);
		if (defined('WP_DEBUG') && WP_DEBUG) {
			$this->logger->log('DEBUG', ['message' => '[Digital Apps Adyen] Card state received: ' . ($card_state ? 'Yes (' . strlen($card_state) . ' chars)' : 'No')]);
		}

		if (empty(trim($card_state))) {
			if (defined('WP_DEBUG') && WP_DEBUG) {
				$this->logger->log('ERROR', ['message' => '[Digital Apps Adyen] Payment data is missing from frontend']);
			}

			$this->create_error_response(
				$payment_result,
				__('Payment data is missing. Please try again.', 'digital-apps-payments-for-adyen')
			);
			return null;
		}

		// Decode the payment state
		$payment_state = json_decode($card_state, true);
		if (defined('WP_DEBUG') && WP_DEBUG) {
			$this->logger->log('ERROR', ['message' => '[Digital Apps Adyen] Decoded payment state: ' . ($payment_state ? 'Success' : 'Failed')]);
		}

		if (!$payment_state || !isset($payment_state['paymentMethod'])) {
			$this->create_error_response(
				$payment_result,
				__('Invalid payment data. Please try again.', 'digital-apps-payments-for-adyen'),
				[],
				'Invalid payment data structure'
			);
			return null;
		}

		$payment_state['paymentMethod'] = map_deep($payment_state['paymentMethod'], 'sanitize_text_field');
		if (isset($payment_state['browserInfo']) && is_array($payment_state['browserInfo'])) {
			$payment_state['browserInfo'] = $this->sanitize_browser_info($payment_state['browserInfo']);
		}

		return $payment_state;
	}

	/**
	 * Sanitize Adyen browser information without changing its schema types.
	 *
	 * @param array $browser_info Browser information supplied by Adyen Web.
	 * @return array
	 */
	private function sanitize_browser_info($browser_info)
	{
		$boolean_value = static function ($value, $default = false) {
			$sanitized = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
			return null === $sanitized ? $default : $sanitized;
		};

		return [
			'acceptHeader' => sanitize_text_field((string) ($browser_info['acceptHeader'] ?? '')),
			'colorDepth' => (int) ($browser_info['colorDepth'] ?? 0),
			'javaEnabled' => $boolean_value($browser_info['javaEnabled'] ?? false),
			'javaScriptEnabled' => $boolean_value($browser_info['javaScriptEnabled'] ?? true, true),
			'language' => sanitize_text_field((string) ($browser_info['language'] ?? '')),
			'screenHeight' => (int) ($browser_info['screenHeight'] ?? 0),
			'screenWidth' => (int) ($browser_info['screenWidth'] ?? 0),
			'timeZoneOffset' => (int) ($browser_info['timeZoneOffset'] ?? 0),
			'userAgent' => sanitize_text_field((string) ($browser_info['userAgent'] ?? '')),
		];
	}

	/**
	 * Prepare and send payment request to Adyen API
	 * 
	 * Creates an Adyen client instance, prepares the payment request data including
	 * payment method and return URL, then sends the payment request to Adyen API.
	 *
	 * @param array $payment_state Decoded payment state containing paymentMethod data from Adyen Web SDK
	 * @param \WC_Order $order The WooCommerce order object for this payment
	 * @return array|null Adyen API response array (contains resultCode, pspReference, etc.) or null on failure
	 */
	private function prepare_and_send_payment_request($payment_state, $order, $return_url = '')
	{
		if (defined('WP_DEBUG') && WP_DEBUG) {
			$this->logger->log('DEBUG', ['message' => '[Digital Apps Adyen] Creating Adyen client...']);
		}

		// Send payment request to Adyen with card data and browserInfo for 3DS
		$client = new Adyen_Client();
		$payment_request_data = [
			'paymentMethod' => $payment_state['paymentMethod'],
			'returnUrl' => $return_url ?: $this->get_return_url($order)
		];

		// Add browserInfo if present (required for 3DS authentication)
		if (isset($payment_state['browserInfo'])) {
			$payment_request_data['browserInfo'] = $payment_state['browserInfo'];
			if (defined('WP_DEBUG') && WP_DEBUG) {
				$this->logger->log('DEBUG', ['message' => '[Digital Apps Adyen] Browser info included in payment request for 3DS']);
			}
		}

		if (defined('WP_DEBUG') && WP_DEBUG) {
			$this->logger->log('DEBUG', ['message' => '[Digital Apps Adyen] Calling Adyen API...']);
		}
		$response = $client->create_payment($order, $payment_request_data);
		if (defined('WP_DEBUG') && WP_DEBUG) {
			$this->logger->log('DEBUG', ['message' => '[Digital Apps Adyen] API response received: ' . ($response ? 'Yes' : 'No')]);
		}

		return $response;
	}

	/**
	 * Extract card state from payment data
	 * 
	 * Handles two different payment data formats from WooCommerce Blocks:
	 * 1. Associative array: ['digitalapps_payments_for_adyen_card_state' => '...']
	 * 2. Key/value pairs list: [{key: 'digitalapps_payments_for_adyen_card_state', value: '...'}]
	 *
	 * @param array $payment_data Payment data from WooCommerce Blocks (format varies by WC version/context)
	 * @return string Card state JSON string from Adyen Web SDK, or empty string if not found
	 */
	private function extract_card_state_from_payment_data($payment_data)
	{
		if (!is_array($payment_data)) {
			return '';
		}

		$keys = array_keys($payment_data);
		$is_associative = array_keys($keys) !== $keys;

		if (defined('WP_DEBUG') && WP_DEBUG) {
			$this->logger->log('DEBUG', ['message' => '[Digital Apps Adyen] Payment data format: ' . ($is_associative ? 'associative' : 'list')]);
		}

		if ($is_associative) {
			// Associative array format: ['digitalapps_payments_for_adyen_card_state' => '...']
			return $payment_data['digitalapps_payments_for_adyen_card_state'] ?? '';
		}

		// List of key/value pairs format: [{key: 'digitalapps_payments_for_adyen_card_state', value: '...'}]
		foreach ($payment_data as $item) {
			if (is_array($item) && isset($item['key']) && $item['key'] === 'digitalapps_payments_for_adyen_card_state') {
				return $item['value'] ?? '';
			}
		}

		return '';
	}

	/**
	 * Handle Adyen payment response
	 * 
	 * Processes the Adyen API response and updates order status based on result code.
	 * Handles various scenarios:
	 * - Authorised: Completes payment (automatic) or sets to on-hold (manual capture)
	 * - RedirectShopper: Initiates 3D Secure authentication flow
	 * - Refused: Creates error response with refusal reason
	 * - Other codes: Generic error handling
	 *
	 * @param array|null $response Adyen API response array (resultCode, pspReference, action, error, etc.)
	 * @param \WC_Order $order The WooCommerce order object to update
	 * @param \Automattic\WooCommerce\StoreApi\Payments\PaymentResult $payment_result Payment result object to update with status
	 * @return void
	 */
	private function handle_payment_response($response, $order, &$payment_result, $session_key = '')
	{
		$settings = get_option('digitalapps_payments_for_adyen_settings', []);
		$capture_mode = $settings['captureMode'] ?? self::CAPTURE_MODE_AUTOMATIC;
		$response = is_array($response) ? $response : [];
		$classification = \DigitalApps\PaymentsForAdyen\Adyen_Result::classify($response);
		\DigitalApps\PaymentsForAdyen\Adyen_Result::apply_to_order($order, $response, $capture_mode);
		$session_manager = new \DigitalApps\PaymentsForAdyen\Adyen_Session_Manager();

		if (\DigitalApps\PaymentsForAdyen\Adyen_Result::ACTION === $classification && $session_key) {
			$updated = $session_manager->update_session($session_key, [
				'payment_data' => $response['paymentData'] ?? '',
				'action' => $response['action'],
			]);
			if ($updated) {
				$payment_result->set_status('success');
				$payment_result->set_redirect_url($session_manager::action_url($session_key));
				return;
			}
		}

		if ($session_key) {
			$session_manager->delete_session($session_key);
		}
		if (in_array($classification, [
			\DigitalApps\PaymentsForAdyen\Adyen_Result::AUTHORISED,
			\DigitalApps\PaymentsForAdyen\Adyen_Result::PENDING,
		], true)) {
			$payment_result->set_status('success');
			$payment_result->set_redirect_url($this->get_return_url($order));
			return;
		}

		$this->create_error_response(
			$payment_result,
			\DigitalApps\PaymentsForAdyen\Adyen_Result::shopper_message($classification),
			[],
			'Adyen payment result classified as ' . $classification
		);
	}

	/**
	 * Create a standardized error response
	 * 
	 * Sets payment result to failure status and populates error details. Optionally logs
	 * the error when WP_DEBUG is enabled. Allows separate user-facing and log messages
	 * for better debugging without exposing technical details to customers.
	 * 
	 * @param \Automattic\WooCommerce\StoreApi\Payments\PaymentResult $payment_result Payment result object to update with failure status
	 * @param string $error_message User-facing error message to display at checkout
	 * @param array $additional_details Optional non-sensitive payment details.
	 * @param string $log_message Optional custom message for error log (if empty, uses $error_message)
	 * @return void
	 */
	private function create_error_response(&$payment_result, $error_message, $additional_details = [], $log_message = '')
	{
		// Log the error
		$log_text = !empty($log_message) ? $log_message : $error_message;
		if (defined('WP_DEBUG') && WP_DEBUG) {
			$this->logger->log('ERROR', ['message' => '[Digital Apps Adyen] Error: ' . $log_text]);
		}

		// Set payment result to failure
		$payment_result->set_status('failure');

		// Build payment details with error message and any additional details
		$payment_details = array_merge(
			['error' => $error_message],
			$additional_details
		);

		$payment_result->set_payment_details($payment_details);
	}

}
