<?php
/**
 * Base Payment Gateway Class
 *
 * @package FunnelKit_Square
 * @subpackage Payment
 */

namespace FKWCSQ\Includes\Modules\Payment\Gateways;

use FKWCSQ\Includes\Logger;
use FKWCSQ\Includes\Traits\Instance;
use FKWCSQ\Includes\Traits\Subscription;
use WC_Order;
use Exception;
use WP_Error;
use WC_Payment_Token_CC;
use WC_Payment_Tokens;

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

/**
 * Card Class
 */
#[\AllowDynamicProperties]
class Card extends \WC_Payment_Gateway {
	use Instance;
	use Subscription;

	/**
	 * Gateway ID.
	 *
	 * @var string
	 */
	public $id = 'fkwcsq_square';
	/**
	 * API instance for Square integration.
	 *
	 * @var \FKWCSQ\Includes\API
	 */
	protected $api;
	/**
	 * Payment capture method setting.
	 *
	 * @var string
	 */
	protected $capture_method;

	/**
	 * List of accepted card types.
	 *
	 * @var array
	 */
	protected $accepted_cards;

	/**
	 * General plugin settings.
	 *
	 * @var array
	 */
	protected $general_settings;

	/**
	 * Whether logging is enabled.
	 *
	 * @var bool
	 */
	protected $logging_enabled;

	/**
	 * Whether to create customers in Square.
	 *
	 * @var bool
	 */
	protected $create_customer;

	/**
	 * Whether to enable payment tokenization.
	 *
	 * @var bool
	 */
	protected $tokenization;

	/**
	 * Constructor.
	 */
	public function __construct() {
		$this->setup_gateway_properties();
		$this->init_form_fields();
		$this->init_settings();
		$this->load_settings();
		$this->init_hooks();
	}

	/**
	 * Set up basic gateway properties
	 */
	public function setup_gateway_properties() {
		$this->has_fields         = true;
		$this->method_title       = __( 'Square Credit Card', 'funnelkit-payment-gateway-square-for-woocommerce' );
		$this->method_description = __( 'Accept credit card payments using Square.', 'funnelkit-payment-gateway-square-for-woocommerce' );
		$this->supports           = array(
			'products',
			'refunds',
			'tokenization',
			'add_payment_method',
			'custom_order_tables',
			'orders_cache',
		);

		// Initialize subscription support from trait
		$this->init_subscription_support();

		$this->api = \FKWCSQ\Includes\API::get_instance();
	}

	/**
	 * Load settings from database
	 */
	public function load_settings() {
		// Get gateway settings
		$stored_settings = get_option( 'woocommerce_fkwcsq_square_settings', array() );
		// Load general settings
		$this->general_settings = get_option( 'fkwcsq_settings', array() );
		$this->logging_enabled  = isset( $this->general_settings['enable_logging'] ) && $this->general_settings['enable_logging'] === 'yes';
		$this->create_customer  = isset( $this->general_settings['create_customer'] ) && $this->general_settings['create_customer'] === 'yes';
		$this->tokenization     = isset( $stored_settings['tokenization'] ) && $stored_settings['tokenization'] === 'yes';
		$this->title            = $this->get_option( 'title' );
		$this->description      = $this->get_option( 'description' );
		$this->capture_method   = $this->get_option( 'capture_method' );
	}

	/**
	 * Initialize action hooks
	 */
	public function init_hooks() {

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

		// Initialize subscription hooks
		$this->init_subscription_hooks();

		// Token synchronization hook - sync tokens from Square API
		add_action( 'woocommerce_get_customer_payment_tokens', array( $this, 'maybe_sync_gateway_tokens' ), 8, 3 );

		// Token deletion hook
		add_action( 'woocommerce_payment_token_deleted', array( $this, 'detach_customer_token' ), 10, 2 );

		// Remove default credit card form
		remove_action( 'woocommerce_credit_card_form_start', array( $this, 'credit_card_form_start' ) );
		remove_action( 'woocommerce_credit_card_form_end', array( $this, 'credit_card_form_end' ) );
	}

	/**
	 * Initialize form fields
	 */
	public function init_form_fields() {
		$this->form_fields = array(
			'enabled'        => array(
				'title'       => __( 'Enable Square Credit Card', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'label'       => ' ',
				'type'        => 'checkbox',
				'description' => '',
				'default'     => 'no',
			),
			'title'          => array(
				'title'       => __( 'Title', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'type'        => 'text',
				'description' => __( 'This controls the title which the user sees during checkout.', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'default'     => __( 'Square Credit Card', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'desc_tip'    => true,
			),
			'description'    => array(
				'title'       => __( 'Description', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'type'        => 'textarea',
				'description' => __( 'This controls the description which the user sees during checkout.', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'default'     => __( 'Pay securely using your credit card.', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'desc_tip'    => true,
			),
			'capture_method' => array(
				'title'       => __( 'Charge Type', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'type'        => 'select',
				'description' => __( 'Choose whether to capture payments immediately or authorize only and capture later.', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'default'     => 'automatic',
				'desc_tip'    => true,
				'options'     => array(
					'automatic' => __( 'Capture immediately', 'funnelkit-payment-gateway-square-for-woocommerce' ),
					'manual'    => __( 'Authorize only (capture manually)', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				),
			),
			'accepted_cards' => array(
				'title'       => __( 'Allowed Card Brands', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'type'        => 'multiselect',
				'class'       => 'fkwcs_select_woo',
				'description' => __( 'Select which card types to accept.', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'default'     => array( 'visa', 'mastercard', 'amex', 'discover' ),
				'desc_tip'    => true,
				'options'     => array(
					'visa'       => __( 'Visa', 'funnelkit-payment-gateway-square-for-woocommerce' ),
					'mastercard' => __( 'Mastercard', 'funnelkit-payment-gateway-square-for-woocommerce' ),
					'amex'       => __( 'American Express', 'funnelkit-payment-gateway-square-for-woocommerce' ),
					'discover'   => __( 'Discover', 'funnelkit-payment-gateway-square-for-woocommerce' ),
					'diners'     => __( 'Diners Club', 'funnelkit-payment-gateway-square-for-woocommerce' ),
					'jcb'        => __( 'JCB', 'funnelkit-payment-gateway-square-for-woocommerce' ),
					'unionpay'   => __( 'UnionPay', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				),
			),
			'tokenization'   => array(
				'title'       => __( 'Saved Cards', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'label'       => __( 'Enable Payment via Saved Cards', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'type'        => 'checkbox',
				'description' => __( 'Allow customers to save their cards for future purchases.', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'default'     => 'no',
				'desc_tip'    => true,
			),
		);
	}


	/**
	 * Override the default get_icon method to display multiple card icons
	 *
	 * @return string
	 */
	public function get_icon() {
		$accepted_cards = $this->get_accepted_cards();
		$icon_html      = '';

		$card_icons = array(
			'visa'       => 'card-visa.svg',
			'mastercard' => 'card-mastercard.svg',
			'amex'       => 'card-amex.svg',
			'discover'   => 'card-discover.svg',
			'diners'     => 'card-dinersclub.svg',
			'jcb'        => 'card-jcb.svg',
			'unionpay'   => 'card-unionpay.svg',
		);

		if ( empty( $accepted_cards ) ) {
			$accepted_cards = array( 'visa' );
		}

		foreach ( $accepted_cards as $card ) {
			if ( isset( $card_icons[ $card ] ) ) {
				$icon_url   = FKWCSQ_PLUGIN_URL . 'assets/images/' . $card_icons[ $card ];
				$icon_html .= sprintf( '<img src="%s" alt="%s" class="sv-wc-payment-gateway-icon wc-%s-payment-gateway-icon" width="32" style="margin-left: 0.3em" />', esc_url( $icon_url ), esc_attr( ucfirst( $card ) ), esc_attr( 'funnelkit-payment-gateway-square-for-woocommerce' ) );
			}
		}

		return apply_filters( 'woocommerce_gateway_icon', $icon_html, $this->id );
	}

	/**
	 * Process payment
	 *
	 * @param int $order_id Order ID
	 *
	 * @return array
	 */
	public function process_payment( $order_id ) {
		try {

			$order = $this->get_order( $order_id );

			if ( $this->maybe_change_subscription_payment_method( $order_id ) ) {
				return $this->process_change_subscription_payment_method( $order, true );
			}

			if ( 0 >= $order->get_total() ) {
				return $this->process_change_subscription_payment_method( $order );
			}

			// Check if using saved card
			if ( 'fkwcsq_square' === $this->id && isset( $_POST['wc-fkwcsq_square-payment-token'] ) && $_POST['wc-fkwcsq_square-payment-token'] !== 'new' ) { //phpcs:ignore WordPress.Security.NonceVerification.Missing, FKWCS.CodeAnalysis.FKWCSSpecific.MissingCapabilityCheck -- WooCommerce handles nonce verification for checkout, guest users allowed
				return $this->process_payment_with_token( $order, wc_clean( wp_unslash( $_POST['wc-fkwcsq_square-payment-token'] ) ) ); //phpcs:ignore WordPress.Security.NonceVerification.Missing, FKWCS.CodeAnalysis.FKWCSSpecific.MissingCapabilityCheck -- WooCommerce handles nonce verification for checkout, guest users allowed
			}

			$payment_data = $this->prepare_payment_data( $order );

			return $this->execute_payment( $order, $payment_data );
		} catch ( Exception $e ) {
			return $this->handle_payment_error( $e, $order_id );
		}
	}

	/**
	 * Process payment with saved card
	 *
	 * @param WC_Order $order
	 * @param string   $token_id
	 *
	 * @return array
	 * @throws Exception
	 */
	public function process_payment_with_token( $order, $token_id ) {
		try {
			$this->log_debug( 'Processing payment with token: ' . $token_id . ' for order #' . $order->get_id() );

			// Get the token
			$token = WC_Payment_Tokens::get( $token_id );

			if ( ! $token || $token->get_user_id() !== get_current_user_id() ) {
				throw new Exception( __( 'Invalid payment token.', 'funnelkit-payment-gateway-square-for-woocommerce' ) );
			}

			// Get Square customer ID and card ID from token
			$square_customer_id = get_user_meta( get_current_user_id(), '_square_customer_id', true );

			// If we don't have a customer ID stored in user meta, try from token meta
			if ( empty( $square_customer_id ) ) {
				$square_customer_id = $token->get_meta( '_square_customer_id' );
			}

			// Get the card ID from token - this should be the token itself for Square
			$square_card_id = $token->get_token();

			// Validate we have the required data
			if ( empty( $square_customer_id ) ) {
				$this->log_error( 'Missing Square customer ID for token: ' . $token_id );
				throw new Exception( __( 'Missing customer information. Please try a different payment method.', 'funnelkit-payment-gateway-square-for-woocommerce' ) );
			}

			if ( empty( $square_card_id ) ) {
				$this->log_error( 'Missing Square card ID for token: ' . $token_id );
				throw new Exception( __( 'Invalid card information. Please try a different payment method.', 'funnelkit-payment-gateway-square-for-woocommerce' ) );
			}

			$this->log_debug( 'Using Square customer ID: ' . $square_customer_id . ' and card ID: ' . $square_card_id );
			$verification_token = isset( $_POST['fkwcsq_verification_token'] ) ? sanitize_text_field( wp_unslash( $_POST['fkwcsq_verification_token'] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Missing, FKWCS.CodeAnalysis.FKWCSSpecific.MissingCapabilityCheck -- WooCommerce handles nonce verification for checkout, guest users allowed

			// Prepare payment data
			$payment_data = array(
				'idempotency_key' => \fkwcsq_idempotency_key( 'fkwcsq_payment_' ),
				'amount_money'    => array(
					'amount'   => (int) ( $order->get_total() * 100 ), // Convert to cents
					'currency' => $order->get_currency(),
				),
				'source_id'       => $square_card_id,
				'customer_id'     => $square_customer_id,
				'location_id'     => $this->api->get_location_id(),
				'autocomplete'    => $this->capture_method === 'automatic',
				'reference_id'    => $this->api->get_reference_id( $order->get_order_number() ), // max 40 chars
				/* translators: %s: Order number */
				'note'            => sprintf( __( 'WooCommerce Order #%s - Payment with saved card', 'funnelkit-payment-gateway-square-for-woocommerce' ), $order->get_order_number() ),
			);
			if ( ! empty( $verification_token ) ) {
				$payment_data['verification_token'] = $verification_token;
				$this->log_debug( 'Added verification token to payment request' );
			}
			// Add billing address
			$payment_data['billing_address'] = $this->format_address( $order, 'billing' );

			// Add shipping address if needed
			if ( $order->needs_shipping_address() ) {
				$payment_data['shipping_address'] = $this->format_address( $order, 'shipping' );
			}

			$this->log_debug( 'Payment data for saved card: ' . wp_json_encode( $payment_data, true ) );

			// Process payment through API
			$response = $this->api->create_payment( $payment_data );

			if ( is_wp_error( $response ) ) {
				throw new Exception( $response->get_error_message() );
			}

			if ( ! isset( $response['payment'] ) || ! isset( $response['payment']['id'] ) ) {
				throw new Exception( __( 'Invalid payment response from Square.', 'funnelkit-payment-gateway-square-for-woocommerce' ) );
			}

			$payment = $response['payment'];

			// Update order meta
			$order->update_meta_data( '_square_payment_id', $payment['id'] );
			$order->update_meta_data( '_square_payment_status', $payment['status'] );
			$order->update_meta_data( '_square_customer_id', $square_customer_id );
			$order->update_meta_data( '_square_payment_token', $square_card_id );
			if ( isset( $payment['card_details'] ) && isset( $payment['card_details']['card'] ) ) {
				$card = $payment['card_details']['card'];
				if ( isset( $card['last_4'] ) ) {
					$order->update_meta_data( '_square_card_last4', $card['last_4'] );
				}
				if ( isset( $card['card_brand'] ) ) {
					$order->update_meta_data( '_square_card_brand', $card['card_brand'] );
				}
			}
			$order->save_meta_data();

			// Update subscription meta if order contains subscriptions
			$this->update_subscription_payment_meta( $order, $square_card_id, $square_customer_id );
			// Handle payment status
			if ( $payment['status'] === 'COMPLETED' ) {
				$order->payment_complete( $payment['id'] );
			} elseif ( $payment['status'] === 'APPROVED' ) {
				/* translators: %s: Square Payment ID */
				$order->update_status( 'on-hold', sprintf( __( 'Payment authorized via saved card (Square Payment ID: %s). Awaiting capture.', 'funnelkit-payment-gateway-square-for-woocommerce' ), $payment['id'] ) );
			} else {
				$this->handle_fail_payment_status( $payment['status'] );
			}

			$order->save();

			return array(
				'result'   => 'success',
				'redirect' => $this->get_return_url( $order ),
			);

		} catch ( Exception $e ) {
			$this->log_error( 'Saved card payment failed: ' . $e->getMessage() );

			return $this->handle_payment_error( $e, $order->get_id() );
		}
	}

	/**
	 * Get and validate order
	 *
	 * @param int $order_id
	 *
	 * @return WC_Order
	 * @throws Exception
	 */
	public function get_order( $order_id ) {
		$order = wc_get_order( $order_id );

		if ( ! $order ) {
			throw new Exception( esc_html__( 'Order not found.', 'funnelkit-payment-gateway-square-for-woocommerce' ) );
		}

		return $order;
	}

	/**
	 * Prepare all payment data needed for Square API
	 *
	 * @param WC_Order $order
	 *
	 * @return array
	 * @throws Exception
	 */
	public function prepare_payment_data( $order ) {
		// Get and validate payment nonce
		$payment_nonce      = $this->get_payment_nonce();
		$verification_token = isset( $_POST['fkwcsq_verification_token'] ) ? sanitize_text_field( wp_unslash( $_POST['fkwcsq_verification_token'] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Missing, FKWCS.CodeAnalysis.FKWCSSpecific.MissingCapabilityCheck -- WooCommerce handles nonce verification for checkout, guest users allowed

		// Generate a unique idempotency key
		$idempotency_key = \fkwcsq_idempotency_key( 'fkwcsq_payment_' );

		// Get location ID
		$location_id = $this->api->get_location_id();

		// Format amount and currency
		$amount   = (int) round( $order->get_total() * 100 ); // Convert to cents
		$currency = $order->get_currency();

		// Prepare basic payment data
		$payment_data = array(
			'source_id'           => $payment_nonce,
			'idempotency_key'     => $idempotency_key,
			'amount_money'        => array(
				'amount'   => $amount,
				'currency' => $currency,
			),
			'location_id'         => $location_id,
			'reference_id'        => $this->api->get_reference_id( $order->get_order_number() ), // max 40 chars
			'buyer_email_address' => $order->get_billing_email(),
			'billing_address'     => $this->format_address( $order, 'billing' ),
			'note'                => $this->get_payment_note( $order ),
			'line_items'          => $this->get_line_items( $order ),
			'autocomplete'        => $this->capture_method === 'automatic',
		);

		// Add shipping address if needed
		if ( $order->needs_shipping_address() ) {
			$payment_data['shipping_address'] = $this->format_address( $order, 'shipping' );
		}

		// Add verification token if present
		if ( ! empty( $verification_token ) ) {
			$payment_data['verification_token'] = $verification_token;
		}

		$this->log_debug( 'Payment data for order #' . $order->get_id() . ': ' . wp_json_encode( $payment_data, true ) );

		return $payment_data;
	}

	/**
	 * Format address for Square API
	 *
	 * @param WC_Order $order
	 * @param string   $type 'billing' or 'shipping'
	 *
	 * @return array
	 */
	public function format_address( $order, $type = 'billing' ) {
		return array(
			'address_line_1'                  => $order->{"get_{$type}_address_1"}(),
			'address_line_2'                  => $order->{"get_{$type}_address_2"}(),
			'locality'                        => $order->{"get_{$type}_city"}(),
			'administrative_district_level_1' => $order->{"get_{$type}_state"}(),
			'postal_code'                     => $order->{"get_{$type}_postcode"}(),
			'country'                         => $order->{"get_{$type}_country"}(),
		);
	}

	/**
	 * Get payment nonce from POST data
	 *
	 * @return string
	 * @throws Exception
	 */
	public function get_payment_nonce() {
		$payment_nonce = isset( $_POST['fkwcsq_square_nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['fkwcsq_square_nonce'] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Missing, FKWCS.CodeAnalysis.FKWCSSpecific.MissingCapabilityCheck -- WooCommerce handles nonce verification for checkout, guest users allowed

		if ( empty( $payment_nonce ) ) {
			throw new Exception( esc_html__( 'Payment nonce is missing. Please try again.', 'funnelkit-payment-gateway-square-for-woocommerce' ) );
		}

		return $payment_nonce;
	}

	/**
	 * Create payment note for Square
	 *
	 * @param WC_Order $order
	 *
	 * @return string
	 */
	public function get_payment_note( $order ) {
		/* translators: 1: Order number, 2: Billing first name, 3: Billing last name */
		return sprintf( __( 'WooCommerce: Order #%1$s %2$s %3$s', 'funnelkit-payment-gateway-square-for-woocommerce' ), $order->get_order_number(), $order->get_billing_first_name(), $order->get_billing_last_name() );
	}

	/**
	 * Format line items for Square
	 *
	 * @param WC_Order $order
	 *
	 * @return array
	 */
	public function get_line_items( $order ) {
		$line_items = array();
		$currency   = $order->get_currency();

		foreach ( $order->get_items() as $item ) {
			$product  = $item instanceof \WC_Order_Item_Product ? $item->get_product() : null;
			$quantity = $item->get_quantity();

			// Calculate base price (total / quantity)
			$item_total = 0;
			if ( $item instanceof \WC_Order_Item_Product ) {
				$item_total = $item->get_total();
			}
			$base_price = $quantity > 0 ? $item_total / $quantity : 0;

			$line_item = array(
				'name'              => $item->get_name(),
				'quantity'          => (string) $quantity,
				'base_price_money'  => array(
					'amount'   => (int) round( $base_price * 100 ), // Convert to cents
					'currency' => $currency,
				),
				'total_price_money' => array(
					'amount'   => (int) round( $item_total * 100 ), // Convert to cents
					'currency' => $currency,
				),
			);

			// Add optional product details
			if ( $product ) {
				$line_item['product_id'] = (string) $product->get_id();

				// Add SKU if available
				$sku = $product->get_sku();
				if ( ! empty( $sku ) ) {
					$line_item['sku'] = $sku;
				}
			}

			$line_items[] = $line_item;
		}

		return $line_items;
	}

	/**
	 * Log debug message if logging is enabled
	 *
	 * @param string $message
	 */
	public function log_debug( $message ) {
		if ( $this->logging_enabled ) {
			Logger::debug( $message );
		}
	}

	/**
	 * Log error message if logging is enabled
	 *
	 * @param string $message
	 */
	public function log_error( $message ) {
		if ( $this->logging_enabled ) {
			Logger::error( $message );
		}
	}

	/**
	 * Execute payment and handle the response
	 *
	 * @param WC_Order $order
	 * @param array    $payment_data
	 *
	 * @return array
	 * @throws Exception
	 */
	public function execute_payment( $order, $payment_data ) {
		// Process payment
		$response = $this->api->create_payment( $payment_data );
		if ( is_wp_error( $response ) ) {
			$this->log_error( 'Payment failed with error: ' . $response->get_error_message() );
			throw new Exception( esc_html( $response->get_error_message() ) );
		}

		// Check for verification required error
		if ( isset( $response['errors'] ) ) {
			return $this->handle_response_errors( $response );
		}

		if ( ! isset( $response['payment'] ) || ! isset( $response['payment']['id'] ) ) {
			throw new Exception( esc_html__( 'Invalid payment response from Square.', 'funnelkit-payment-gateway-square-for-woocommerce' ) );
		}

		if ( $this->supports( 'tokenization' ) ) {
			$this->save_payment_token( $order, $response['payment'] );
		}

		return $this->process_successful_payment( $order, $response['payment'], $payment_data['location_id'] );
	}

	/**
	 * Handle response errors
	 *
	 * @param array $response
	 *
	 * @return array
	 * @throws Exception
	 */
	public function handle_response_errors( $response ) {
		foreach ( $response['errors'] as $error ) {
			if ( isset( $error['code'] ) && $error['code'] === 'CARD_DECLINED_VERIFICATION_REQUIRED' ) {
				$this->log_debug( 'Verification required for payment' );

				return array(
					'result'               => 'requires_verification',
					'verification_details' => isset( $error['verification_details'] ) ? $error['verification_details'] : array(),
				);
			}
		}

		// Handle other errors
		$error_message = $this->format_error_message( $response['errors'] );
		throw new Exception( esc_html( $error_message ) );
	}

	/**
	 * Format error message from multiple errors
	 *
	 * @param array $errors
	 *
	 * @return string
	 */
	public function format_error_message( $errors ) {
		$error_message = '';
		foreach ( $errors as $error ) {
			$error_message .= isset( $error['detail'] ) ? $error['detail'] . ' ' : '';
		}

		return $error_message;
	}

	/**
	 * Process successful payment
	 *
	 * @param WC_Order $order
	 * @param array    $payment
	 * @param string   $location_id
	 *
	 * @return array
	 * @throws Exception
	 */
	public function process_successful_payment( $order, $payment, $location_id ) {
		$payment_status = $payment['status'];

		$this->update_payment_meta( $order, $payment, $location_id );

		switch ( $payment_status ) {
			case 'APPROVED':
				$this->handle_approved_payment( $order, $payment );
				break;
			case 'COMPLETED':
				// Only handle completed payment if 'fkwcsq_order_hold' has not been triggered
				if ( 0 === did_action( 'fkwcsq_order_hold' ) ) {
					$this->handle_completed_payment( $order, $payment );
				}
				break;
			default:
				$this->handle_fail_payment_status( $payment_status );
				break;
		}

		// Maybe create Square customer
		$this->maybe_create_customer( $order );

		$order->save();

		return array(
			'result'   => 'success',
			'redirect' => $this->get_return_url( $order ),
		);
	}

	/**
	 * Update payment meta data
	 *
	 * @param WC_Order $order
	 * @param array    $payment
	 * @param string   $location_id
	 */
	public function update_payment_meta( $order, $payment, $location_id ) {
		$order->update_meta_data( '_square_payment_id', $payment['id'] );
		$order->update_meta_data( '_square_payment_status', $payment['status'] );
		$order->update_meta_data( '_square_location_id', $location_id );
		if ( isset( $payment['order_id'] ) ) {
			$order->update_meta_data( '_square_order_id', $payment['order_id'] );
		}

		if ( isset( $payment['card_details'] ) && isset( $payment['card_details']['card'] ) ) {
			$card = $payment['card_details']['card'];
			if ( isset( $card['last_4'] ) ) {
				$order->update_meta_data( '_square_card_last4', $card['last_4'] );
			}
			if ( isset( $card['card_brand'] ) ) {
				$order->update_meta_data( '_square_card_brand', $card['card_brand'] );
			}
		}
	}

	/**
	 * Handle approved payment status
	 *
	 * @param WC_Order $order
	 * @param array    $payment
	 */
	public function handle_approved_payment( $order, $payment ) {
		/* translators: %s: Payment ID */
		$order->update_status( 'on-hold', sprintf( __( 'Square payment authorized, Awaiting capture. (Payment ID: %s)', 'funnelkit-payment-gateway-square-for-woocommerce' ), $payment['id'] ) );

		/* translators: %s: Payment ID */
		$this->log_debug( sprintf( __( 'Square payment authorized (Payment ID: %s)', 'funnelkit-payment-gateway-square-for-woocommerce' ), $payment['id'] ) );
	}

	/**
	 * Handle completed payment status
	 *
	 * @param WC_Order $order
	 * @param array    $payment
	 */
	public function handle_completed_payment( $order, $payment ) {
		$order->payment_complete( $payment['id'] );
		/* translators: %s: Payment ID */
		$this->log_debug( sprintf( __( 'Square payment completed (Payment ID: %s)', 'funnelkit-payment-gateway-square-for-woocommerce' ), $payment['id'] ) );
	}

	/**
	 * Handle other payment status
	 *
	 * @param string $payment_status
	 *
	 * @throws Exception
	 */
	public function handle_fail_payment_status( $payment_status ) {
		/* translators: %s: Payment status */
		$this->log_debug( sprintf( __( 'Payment not completed. Status: %s', 'funnelkit-payment-gateway-square-for-woocommerce' ), $payment_status ) );
		/* translators: %s: Payment status */
		throw new Exception( esc_html( sprintf( __( 'Payment not completed. Status: %s', 'funnelkit-payment-gateway-square-for-woocommerce' ), $payment_status ) ) );
	}

	/**
	 * Get the transaction URL linked to Square dashboard
	 *
	 * @param $order
	 *
	 * @return string
	 */
	public function get_transaction_url( $order ) {
		if ( ! \FKWCSQ\Square::is_sandbox_mode() ) {
			$this->view_transaction_url = 'https://squareup.com/dashboard/sales/transactions/%s';
		} else {
			$this->view_transaction_url = 'https://squareupsandbox.com/dashboard/sales/transactions/%s';
		}

		return parent::get_transaction_url( $order );
	}

	/**
	 * Maybe create a Square customer
	 *
	 * @param WC_Order $order
	 */
	public function maybe_create_customer( $order ) {
		if ( $this->create_customer ) {
			$customer_result = $this->api->maybe_create_customer( $order );

			if ( ! is_wp_error( $customer_result ) && isset( $customer_result['customer_id'] ) ) {
				$order->update_meta_data( '_square_customer_id', $customer_result['customer_id'] );
			}
		}
	}

	/**
	 * Handle payment errors
	 *
	 * @param Exception $e
	 * @param int       $order_id
	 *
	 * @return array
	 */
	public function handle_payment_error( $e, $order_id ) {
		$this->log_error( 'Payment processing failed for order #' . $order_id . ': ' . $e->getMessage() );

		// Get order if available but wasn't passed
		$order = wc_get_order( $order_id );

		// Add failure note to order
		if ( $order ) {
			/* translators: %s: Error message */
			$order->update_status( 'failed', sprintf( __( 'Payment failed via Square. %s', 'funnelkit-payment-gateway-square-for-woocommerce' ), $e->getMessage() ) );
		}

		wc_add_notice( $e->getMessage(), 'error' );

		return array(
			'result'   => 'fail',
			'redirect' => '',
		);
	}

	/**
	 * Save payment token for future use
	 *
	 * @param WC_Order $order The order object.
	 * @param array    $payment Square payment data.
	 *
	 * @return void
	 * @throws Exception When token cannot be saved or customer creation fails.
	 */
	public function save_payment_token( $order, $payment ) {
		try {
			$this->log_debug( 'Starting card save process for order #' . $order->get_id() );

			// Check for required card details
			if ( ! isset( $payment['card_details'] ) || ! isset( $payment['card_details']['card'] ) ) {
				$this->log_error( 'Missing required card details in payment data.' );

				return;
			}

			$card_details = $payment['card_details'];
			$card         = $card_details['card'];

			// First ensure we have a customer ID
			$customer_id = $this->get_or_create_customer( $order );
			if ( empty( $customer_id ) ) {
				/* translators: %s: Error message */
				$order->update_status( 'on-hold',  __( 'Customer creation failed via Square.', 'funnelkit-payment-gateway-square-for-woocommerce' )  );
				return;
			}

			// Create card using Square Cards API
			$card_data = $this->prepare_card_data( $order, $payment, $customer_id );

			$response = $this->api->create_card( $card_data, $order );

			if ( is_wp_error( $response ) ) {
				$this->log_error( 'Error from Square Cards API: ' . $response->get_error_message() );
				throw new Exception( 'Error from Square Cards API: ' . $response->get_error_message() );
			} elseif ( ! isset( $response['card'] ) || ! isset( $response['card']['id'] ) ) {
				$this->log_error( 'Invalid response from Square Cards API: ' . wp_json_encode( $response, true ) );
				throw new Exception( 'Invalid response from Square Cards API' );
			}

			$square_card = $response['card'];
			$order->update_meta_data( '_square_customer_id', $customer_id );
			$order->update_meta_data( '_square_payment_token', $square_card['id'] );
			$order->save_meta_data();

			// Update subscription meta if order contains subscriptions
			$this->update_subscription_payment_meta( $order, $square_card['id'], $customer_id );

			if ( $this->tokenization && is_user_logged_in() && isset( $_POST['fkwcsq_square_save_card'] ) && $_POST['fkwcsq_square_save_card'] === 'true' ) { //phpcs:ignore WordPress.Security.NonceVerification.Missing, FKWCS.CodeAnalysis.FKWCSSpecific.MissingCapabilityCheck -- WooCommerce handles nonce verification for add payment method, guest users allowed
				// Create WooCommerce payment token
				$token = $this->create_wc_token( $square_card, $card, $customer_id );
				// Add token to order
				$order->add_payment_token( $token );
			}
		} catch ( Exception $e ) {
			$this->log_error( 'Failed to save payment token: ' . $e->getMessage() );
		}
	}

	/**
	 * Get or create customer ID
	 *
	 * @param WC_Order $order
	 *
	 * @return string|null
	 */
	public function get_or_create_customer( $order ) {
		$customer_id = $order->get_meta( '_square_customer_id' );

		if ( empty( $customer_id ) ) {
			$this->log_debug( 'No customer ID found, creating new customer' );

			$customer_id = $this->api->maybe_create_customer( $order );
			if ( is_wp_error( $customer_id ) ) {
				$this->log_error( 'Failed to create/get Square customer: ' . ( is_wp_error( $customer_id ) ? $customer_id->get_error_message() : 'No customer ID in response' ) );

				return null;
			}
			$this->log_debug( 'Customer created/found with ID: ' . $customer_id );
		}

		return $customer_id;
	}

	/**
	 * Prepare card data for Square API
	 *
	 * @param WC_Order $order
	 * @param array    $payment
	 * @param string   $customer_id
	 *
	 * @return array
	 */
	public function prepare_card_data( $order, $payment, $customer_id ) {
		$card_data = array(
			'idempotency_key' => \fkwcsq_idempotency_key( 'fkwcsq_card_' ),
			'source_id'       => $payment['id'],
			'card'            => array(
				'billing_address' => array(
					'address_line_1'                  => $order->get_billing_address_1(),
					'address_line_2'                  => $order->get_billing_address_2(),
					'locality'                        => $order->get_billing_city(),
					'administrative_district_level_1' => $order->get_billing_state(),
					'postal_code'                     => $order->get_billing_postcode(),
					'country'                         => $order->get_billing_country(),
					'first_name'                      => $order->get_billing_first_name(),
					'last_name'                       => $order->get_billing_last_name(),
				),
				'customer_id'     => $customer_id,
				'cardholder_name' => $order->get_billing_first_name() . ' ' . $order->get_billing_last_name(),
			),
		);

		if ( isset( $payment['verification_token'] ) ) {
			$card_data['verification_token'] = $payment['verification_token'];
		}

		$this->log_debug( 'Prepared card data: ' . wp_json_encode( $card_data, true ) );

		return $card_data;
	}


	/**
	 * Create WooCommerce payment token
	 *
	 * @param array  $square_card Square card data.
	 * @param array  $card Card details from the payment.
	 * @param string $customer_id Square customer ID.
	 *
	 * @return WC_Payment_Token_CC Created payment token.
	 * @throws Exception When token cannot be saved or data is invalid.
	 */
	public function create_wc_token( $square_card, $card, $customer_id ) {
		$token = new WC_Payment_Token_CC();
		$token->set_token( $square_card['id'] ); // Use Square card ID
		$token->set_gateway_id( $this->id );
		$token->set_card_type( strtolower( $card['card_brand'] ) );
		$token->set_last4( $card['last_4'] );
		$token->set_expiry_month( $card['exp_month'] );
		$token->set_expiry_year( $card['exp_year'] );
		$token->set_user_id( get_current_user_id() );

		$this->log_debug(
			'Created WooCommerce token with data: ' . wp_json_encode(
				array(
					'token'     => $square_card['id'],
					'card_type' => strtolower( $card['card_brand'] ),
					'last4'     => $card['last_4'],
					'expiry'    => $card['exp_month'] . '/' . $card['exp_year'],
					'user_id'   => get_current_user_id(),
				),
				true
			)
		);
		update_user_meta( get_current_user_id(), '_square_customer_id', $customer_id );
		// Save the token
		if ( $token->save() ) {

			$token->update_meta_data( '_square_customer_id', $customer_id );

			// Update transient cache with new payment method
			$user_id = get_current_user_id();
			if ( $user_id ) {
				$this->update_transient_with_new_payment_method( $user_id, $square_card );
			}
		} else {
			$this->log_error( 'Failed to save WooCommerce payment token' );
			throw new Exception( 'Failed to save WooCommerce payment token' );
		}

		return $token;
	}

	/**
	 * Process refund
	 *
	 * @param int    $order_id Order ID
	 * @param float  $amount Refund amount
	 * @param string $reason Refund reason
	 *
	 * @return bool|WP_Error
	 */
	public function process_refund( $order_id, $amount = null, $reason = '' ) {
		try {
			// Process refund through API
			$result = $this->api->process_refund( $order_id, $amount, $reason );

			if ( is_wp_error( $result ) ) {
				return $result;
			}

			return true;
		} catch ( Exception $e ) {
			return new WP_Error( 'refund_error', $e->getMessage() );
		}
	}

	/**
	 * Payment fields
	 */
	public function payment_fields() {
		// Display saved payment methods if available
		if ( is_add_payment_method_page() ) {
			$this->display_add_payment_method_form();
		} else {
			$this->display_checkout_payment_form();
		}
	}

	/**
	 * Display form for adding a new payment method
	 */
	public function display_add_payment_method_form() {
		echo '<div class="fkwcsq-square-payment-form">';
		echo '<div id="square-card-container">';
		echo '</div>';
		echo '<div id="square-card-error" class="woocommerce-error" style="display:none;"></div>';
		echo '</div>';
	}

	/**
	 * Display checkout payment form
	 */
	public function display_checkout_payment_form() {
		if ( $this->description ) {
			echo wp_kses_post( wpautop( $this->description ) );
		}

		if ( did_action( 'wfacp_checkout_before_order_review' ) ) {
			return;
		}

		$this->saved_payment_methods();

		echo '<div class="fkwcsq-square-payment-form">';
		echo '<div id="square-card-container" class="square-shimmer-container">';
		echo '<div class="square-shimmer-line"></div>';
		echo '<div class="square-shimmer-line"></div>';
		echo '<div class="square-shimmer-line"></div>';
		echo '</div>';
		echo '<div id="square-card-error" class="woocommerce-error" style="display:none;"></div>';
		echo '</div>';

		$display_tokenization = apply_filters( 'fkwcsq_square_display_save_payment_method_checkbox', is_user_logged_in(), $this );
		if ( $display_tokenization && $this->tokenization ) {
			echo '<p class="form-row form-row-wide">';
			echo '<label>';
			echo '<input type="checkbox" id="fkwcsq_square_save_card" name="fkwcsq_square_save_card" value="true" />';
			echo esc_html__( 'Save payment information to my account for future purchases.', 'funnelkit-payment-gateway-square-for-woocommerce' );
			echo '</label>';
			echo '</p>';
		} else {
			echo '<input type="hidden" id="fkwcsq_square_save_card" name="fkwcsq_square_save_card" value="true" />';
		}

		if ( \FKWCSQ\Square::is_sandbox_mode() ) {
			echo '<div class="fkwcsq-square-test-card" style="margin-top:10px; color:#000;">';
			echo esc_html__( 'Test Mode Enabled: Use demo card 4111111111111111 with any future date and CVV.  ', 'funnelkit-payment-gateway-square-for-woocommerce' );
			echo '<a href="https://developer.squareup.com/docs/devtools/sandbox/payments" target="_blank" style="color:#000;">';
			echo esc_html__( 'Check more ', 'funnelkit-payment-gateway-square-for-woocommerce' );
			echo '<span style="color:#e74c3c;">' . esc_html__( 'demo cards', 'funnelkit-payment-gateway-square-for-woocommerce' ) . '</span>';
			echo '</a>';
			echo '</div>';
		}
	}

	/**
	 * Enqueue payment scripts
	 */
	public function payment_scripts() {
		// For add payment method page
		if ( is_add_payment_method_page() ) {
			$this->enqueue_add_payment_method_scripts();

			return;
		}

		// For checkout page
		if ( ! is_checkout() || 'no' === $this->enabled ) {
			return;
		}

		$this->enqueue_checkout_scripts();
	}

	/**
	 * Enqueue scripts for add payment method page
	 */
	public function enqueue_add_payment_method_scripts() {
		// Enqueue Square script
		wp_enqueue_script( 'square-payment-form', \FKWCSQ\Square::get_web_sdk_url(), array(), FKWCSQ_VERSION, true );

		// Enqueue add payment method script
		wp_enqueue_script( 'fkwcsq-add-payment-method', FKWCSQ_PLUGIN_URL . 'assets/js/add-payment-method' . $this->api->is_min_suffix() . '.js', array( 'jquery', 'square-payment-form' ), FKWCSQ_VERSION, true );

		// Localize script with params
		wp_localize_script(
			'fkwcsq-add-payment-method',
			'fkwcsq_add_payment_method_params',
			array(
				'application_id'     => \FKWCSQ\Square::get_application_id(),
				'location_id'        => $this->api->get_location_id(),
				'currency'           => get_woocommerce_currency(),
				'billing_first_name' => WC()->customer->get_billing_first_name(),
				'billing_last_name'  => WC()->customer->get_billing_last_name(),
				'billing_email'      => WC()->customer->get_billing_email(),
			)
		);

		// Add shimmer styles for add payment method page
		wp_add_inline_style(
			'woocommerce-inline',
			'
			/* Square Shimmer Effect */
			#square-card-container.square-shimmer-container {
				position: relative;
				background: #f6f7f8;
				border-radius: 8px;
				padding: 20px;
				overflow: hidden;
				min-height: 90px;
				display: flex;
				flex-direction: column;
				gap: 15px;
			}

			#square-card-container.square-shimmer-container .square-shimmer-line {
				height: 20px;
				background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
				background-size: 200% 100%;
				animation: square-shimmer 1.5s infinite;
				border-radius: 4px;
			}

			#square-card-container.square-shimmer-container .square-shimmer-line:nth-child(1) {
				width: 100%;
			}

			#square-card-container.square-shimmer-container .square-shimmer-line:nth-child(2) {
				width: 60%;
			}

			#square-card-container.square-shimmer-container .square-shimmer-line:nth-child(3) {
				width: 40%;
			}

			@keyframes square-shimmer {
				0% {
					background-position: -200% 0;
				}
				100% {
					background-position: 200% 0;
				}
			}

			/* Hide shimmer when card is loaded with smooth transition */
			#square-card-container.square-card-loaded .square-shimmer-line {
				opacity: 0;
				transition: opacity 0.3s ease-out;
				pointer-events: none;
			}

			#square-card-container {
				margin: 1em 0;
			}
			#square-card-container {
				min-height: 90px;
				background: #fff;
				padding: 10px;
				border: 1px solid #ddd;
				border-radius: 4px;
			}
			'
		);
	}

	/**
	 * Enqueue scripts for checkout page
	 */
	/**
	 * Get gateway-specific localize data.
	 *
	 * Only includes data unique to Card gateway. Base data is added by Checkout_Scripts.
	 *
	 * @return array
	 */
	public function get_gateway_data() {
		$billing_data = $this->get_billing_data_for_js();

		return array_merge(
			array(
				'sandbox_mode'   => \FKWCSQ\Square::is_sandbox_mode(),
				'is_checkout'    => is_checkout() && empty( is_wc_endpoint_url( 'order-pay' ) ),
				'is_pay_page'    => is_wc_endpoint_url( 'order-pay' ),
				'amount'         => WC()->cart ? WC()->cart->get_total( '' ) : 0,
				'accepted_cards' => $this->get_accepted_cards(),
			),
			$billing_data
		);
	}

	public function enqueue_checkout_scripts() {
		$checkout_scripts = \FKWCSQ\Includes\Checkout_Scripts::get_instance();
		$checkout_scripts->enqueue_checkout_script();
		$checkout_scripts->localize_gateway_data( 'fkwcsq_card_payment_params', $this->id, $this->get_gateway_data() );

		// Add inline script for token handling.
		$inline_script = 'jQuery(document).ready(function($) {
			$("#wc-' . esc_js( $this->id ) . '-payment-token-new").prop("checked", true);
			$(".payment_method_' . esc_js( $this->id ) . ' .payment-method-new").addClass("active");
		});';
		wp_add_inline_script( 'fkwcsq-checkout', $inline_script );

		// Add styles (same for both modes).
		wp_add_inline_style(
			'woocommerce-inline',
			'
			/* Square Shimmer Effect */
		#square-card-container.square-shimmer-container {
    position: relative;
    background: #f6f7f8;
    padding: 10px 10px 30px 10px;
    overflow: hidden;
    min-height: 50px;
    display: block;
}




			#square-card-container.square-shimmer-container .square-shimmer-line {
			height: 48px;
    width: 31%;
    float: left;
    margin: 0 1%;
				background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
				background-size: 200% 100%;
				animation: square-shimmer 1.5s infinite;
				border-radius: 4px;
			}

			// #square-card-container.square-shimmer-container .square-shimmer-line:nth-child(1) {
			// 	width: 100%;
			// }

			// #square-card-container.square-shimmer-container .square-shimmer-line:nth-child(2) {
			// 	width: 60%;
			// }

			// #square-card-container.square-shimmer-container .square-shimmer-line:nth-child(3) {
			// 	width: 40%;
			// }

			@keyframes square-shimmer {
				0% {
					background-position: -200% 0;
				}
				100% {
					background-position: 200% 0;
				}
			}

			/* Hide shimmer when card is loaded with smooth transition */
			#square-card-container.square-card-loaded .square-shimmer-line {
				opacity: 0;
				transition: opacity 0.3s ease-out;
				pointer-events: none;
			}


			#square-card-error {
				margin-top: 1em;
			}

			#square-card-container {
				margin: 1em 0;
			}
			#square-card-container {
				min-height: 90px;
				background: #fff;
				padding: 10px;
				border: 1px solid #ddd;
				border-radius: 4px;
			}
		'
		);
	}

	/**
	 * Get billing data for 3DS verification
	 *
	 * @return array
	 */
	public function get_billing_data_for_js() {
		$billing_data = array();

		if ( is_checkout_pay_page() ) {
			if ( $order = wc_get_order( $this->get_checkout_pay_page_order_id() ) ) {
				$billing_data = $this->get_billing_data_from_order( $order );
			}
		} elseif ( WC()->customer ) {
			$billing_data = array(
				'billing_first_name' => WC()->customer->get_billing_first_name(),
				'billing_last_name'  => WC()->customer->get_billing_last_name(),
				'billing_email'      => WC()->customer->get_billing_email(),
				'billing_country'    => WC()->customer->get_billing_country(),
				'billing_address_1'  => WC()->customer->get_billing_address_1(),
				'billing_address_2'  => WC()->customer->get_billing_address_2(),
				'billing_state'      => WC()->customer->get_billing_state(),
				'billing_city'       => WC()->customer->get_billing_city(),
				'billing_postcode'   => WC()->customer->get_billing_postcode(),
				'billing_phone'      => WC()->customer->get_billing_phone(),
			);
		}

		return $billing_data;
	}

	public function get_checkout_pay_page_order_id() {
		global $wp;

		if ( isset( $wp->query_vars['order-pay'] ) ) {
			return absint( $wp->query_vars['order-pay'] );
		}

		return false;
	}

	/**
	 * Get billing data from order
	 *
	 * @param WC_Order $order
	 *
	 * @return array
	 */
	public function get_billing_data_from_order( $order ) {
		return array(
			'billing_first_name' => $order->get_billing_first_name(),
			'billing_last_name'  => $order->get_billing_last_name(),
			'billing_email'      => $order->get_billing_email(),
			'billing_country'    => $order->get_billing_country(),
			'billing_address_1'  => $order->get_billing_address_1(),
			'billing_address_2'  => $order->get_billing_address_2(),
			'billing_state'      => $order->get_billing_state(),
			'billing_city'       => $order->get_billing_city(),
			'billing_postcode'   => $order->get_billing_postcode(),
			'billing_phone'      => $order->get_billing_phone(),
		);
	}

	/**
	 * Get accepted card types
	 *
	 * @return array
	 */
	public function get_accepted_cards() {
		$accepted_cards = $this->get_option( 'accepted_cards', array( 'visa', 'mastercard', 'amex', 'discover' ) );

		return is_array( $accepted_cards ) ? $accepted_cards : array();
	}


	/**
	 * Capture authorized payment
	 *
	 * Captures a previously authorized payment and updates the order status.
	 *
	 * @param WC_Order $order The order to capture payment for.
	 *
	 * @return bool|WP_Error True on success, WP_Error on failure.
	 * @throws Exception When payment capture fails or payment ID is missing.
	 */
	public function capture_payment( $order ) {
		try {
			$payment_id = $order->get_meta( '_square_payment_id' );
			if ( empty( $payment_id ) ) {
				throw new Exception( __( 'Square payment ID not found.', 'funnelkit-payment-gateway-square-for-woocommerce' ) );
			}

			$response = $this->api->capture_payment( $payment_id );
			if ( is_wp_error( $response ) ) {
				throw new Exception( $response->get_error_message() );
			}

			if ( isset( $response['payment'] ) && $response['payment']['status'] === 'COMPLETED' ) {
				$order->update_meta_data( '_square_payment_status', 'COMPLETED' );
				if ( class_exists( 'WFOCU_Core' ) ) {
					remove_action( 'woocommerce_pre_payment_complete', array( \WFOCU_Core()->public, 'maybe_setup_upsell' ), 99 );
				}
				$order->payment_complete( $payment_id );
				$order->save();

				return true;
			}

			throw new Exception( __( 'Payment capture failed.', 'funnelkit-payment-gateway-square-for-woocommerce' ) );

		} catch ( Exception $e ) {
			/* translators: %s: Error message */
			$order->add_order_note( sprintf( __( 'Square payment capture failed: %s', 'funnelkit-payment-gateway-square-for-woocommerce' ), $e->getMessage() ) );

			return new WP_Error( 'capture_failed', $e->getMessage() );
		}
	}

	/**
	 * Add payment method page handler
	 *
	 * Processes requests from the "Add Payment Method" page in WooCommerce.
	 * Creates a new payment token for the user's Square payment method.
	 *
	 * @return array Result array with success/failure status and redirect URL.
	 * @throws Exception When validation fails, customer creation fails, or token creation fails.
	 */
	public function add_payment_method() {
		if ( ! is_user_logged_in() ) {
			wc_add_notice( __( 'You must be logged in to add a payment method.', 'funnelkit-payment-gateway-square-for-woocommerce' ), 'error' );

			return array(
				'result'   => 'failure',
				'redirect' => wc_get_endpoint_url( 'payment-methods' ),
			);
		}

		try {
			$order              = $this->create_mock_order();
			$payment_nonce      = $this->get_payment_nonce();
			$verification_token = isset( $_POST['fkwcsq_verification_token'] ) ? sanitize_text_field( wp_unslash( $_POST['fkwcsq_verification_token'] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Missing, FKWCS.CodeAnalysis.FKWCSSpecific.MissingCapabilityCheck -- WooCommerce handles nonce verification for add payment method, guest users allowed

			$customer_id = $this->get_or_create_square_customer_from_order( $order );

			// Create card data

			$card_data = array(
				'idempotency_key' => \fkwcsq_idempotency_key( 'fkwcsq_card_' ),
				'source_id'       => $payment_nonce,
				'card'            => array(
					'billing_address' => array(
						'address_line_1'                  => $order->get_billing_address_1(),
						'address_line_2'                  => $order->get_billing_address_2(),
						'locality'                        => $order->get_billing_city(),
						'administrative_district_level_1' => $order->get_billing_state(),
						'postal_code'                     => $order->get_billing_postcode(),
						'country'                         => $order->get_billing_country(),
						'first_name'                      => $order->get_billing_first_name(),
						'last_name'                       => $order->get_billing_last_name(),
					),
					'customer_id'     => $customer_id,
					'cardholder_name' => $order->get_billing_first_name() . ' ' . $order->get_billing_last_name(),
				),
			);

			// Add verification token if present
			if ( ! empty( $verification_token ) ) {
				$card_data['verification_token'] = $verification_token;
			}

			// Create card in Square
			$response = $this->api->create_card( $card_data, );

			// Handle response
			if ( is_wp_error( $response ) ) {
				throw new Exception( $response->get_error_message() );
			}

			// Validate card response
			if ( ! isset( $response['card'] ) || ! isset( $response['card']['id'] ) ) {
				throw new Exception( __( 'Failed to add payment method.', 'funnelkit-payment-gateway-square-for-woocommerce' ) );
			}

			// Create WooCommerce payment token
			$this->create_payment_token( $response['card'] );

			// Redirect to payment methods page
			return array(
				'result'   => 'success',
				'redirect' => wc_get_endpoint_url( 'payment-methods' ),
			);

		} catch ( Exception $e ) {
			$this->log_error( 'Add payment method error: ' . $e->getMessage() );
			wc_add_notice( $e->getMessage(), 'error' );

			return array(
				'result'   => 'failure',
				'redirect' => wc_get_endpoint_url( 'add-payment-method' ),
			);
		}
	}

	/**
	 * Create a mock order with current user's billing information
	 *
	 * @return WC_Order
	 */
	public function create_mock_order() {
		$user_id = get_current_user_id();
		$order   = new WC_Order();

		$order->set_billing_first_name( get_user_meta( $user_id, 'billing_first_name', true ) );
		$order->set_billing_last_name( get_user_meta( $user_id, 'billing_last_name', true ) );

		// Get email from user meta, fallback to users table user_email
		$billing_email = get_user_meta( $user_id, 'billing_email', true );
		if ( empty( $billing_email ) ) {
			$user = get_userdata( $user_id );
			if ( $user && ! empty( $user->user_email ) ) {
				$billing_email = $user->user_email;
			}
		}
		$order->set_billing_email( $billing_email );

		$order->set_billing_phone( get_user_meta( $user_id, 'billing_phone', true ) );
		$order->set_billing_address_1( get_user_meta( $user_id, 'billing_address_1', true ) );
		$order->set_billing_address_2( get_user_meta( $user_id, 'billing_address_2', true ) );
		$order->set_billing_city( get_user_meta( $user_id, 'billing_city', true ) );
		$order->set_billing_state( get_user_meta( $user_id, 'billing_state', true ) );
		$order->set_billing_postcode( get_user_meta( $user_id, 'billing_postcode', true ) );
		$order->set_billing_country( get_user_meta( $user_id, 'billing_country', true ) );

		// Set customer ID for the order
		$order->set_customer_id( $user_id );

		return $order;
	}

	/**
	 * Get or create Square customer from order
	 *
	 * @param WC_Order $order
	 *
	 * @return string Customer ID
	 * @throws Exception
	 */
	public function get_or_create_square_customer_from_order( $order ) {
		$user_id = get_current_user_id();

		$customer_id = get_user_meta( $user_id, '_square_customer_id', true );

		if ( empty( $customer_id ) ) {
			$customer_id = $this->api->maybe_create_customer( $order );

			if ( is_wp_error( $customer_id ) ) {
				throw new Exception( esc_html( $customer_id->get_error_message() ) );
			}

			update_user_meta( $user_id, '_square_customer_id', $customer_id );
		}

		return $customer_id;
	}

	/**
	 * Create WooCommerce payment token
	 *
	 * Creates and saves a WooCommerce payment token from the Square card data,
	 * storing card details and associating it with the current user.
	 *
	 * @param array $card_data Square card data from the API response.
	 *
	 * @return WC_Payment_Token_CC The created payment token object.
	 * @throws Exception When token cannot be saved or required card data is missing.
	 */
	public function create_payment_token( $card_data ) {
		$token = new WC_Payment_Token_CC();
		$token->set_token( $card_data['id'] );
		$token->set_gateway_id( $this->id );
		$token->set_card_type( strtolower( $card_data['card_brand'] ) );
		$token->set_last4( $card_data['last_4'] );
		$token->set_expiry_month( $card_data['exp_month'] );
		$token->set_expiry_year( $card_data['exp_year'] );
		$token->set_user_id( get_current_user_id() );

		if ( ! $token->save() ) {
			throw new Exception( esc_html__( 'Could not save payment token.', 'funnelkit-payment-gateway-square-for-woocommerce' ) );
		}

		// Store additional metadata
		if ( ! empty( $card_data['customer_id'] ) ) {
			update_user_meta( get_current_user_id(), '_square_customer_id', $card_data['customer_id'] );
			$token->update_meta_data( '_square_customer_id', $card_data['customer_id'] );
		}

		// Update transient cache with new payment method
		$user_id = get_current_user_id();
		if ( $user_id ) {
			$this->update_transient_with_new_payment_method( $user_id, $card_data );
		}

		return $token;
	}

	/**
	 * Override saved_payment_methods to only show radio if tokens exist
	 */
	public function saved_payment_methods() {
		if ( ! is_user_logged_in() || ! $this->tokenization ) {
			return;
		}
		$tokens = WC_Payment_Tokens::get_customer_tokens( get_current_user_id(), $this->id );
		if ( empty( $tokens ) ) {
			return;
		}
		parent::saved_payment_methods();
	}

	/**
	 * Check if the gateway is available for use.
	 *
	 * @return bool
	 */
	public function is_available() {
		$is_available = ( 'yes' === $this->enabled );

		// Check if Square connection is established
		if ( ! \FKWCSQ\Square::is_configured() ) {
			return false;
		}

		if ( WC()->cart && 0 < $this->get_order_total() && 0 < $this->max_amount && $this->max_amount < $this->get_order_total() ) {
			$is_available = false;
		}

		return $is_available;
	}

	/**
	 * Maybe sync gateway tokens from Square API
	 *
	 * @param array  $tokens Array of payment tokens
	 * @param int    $customer_id Customer ID
	 * @param string $gateway_id Gateway ID
	 * @return array Modified tokens array
	 */
	public function maybe_sync_gateway_tokens( $tokens, $customer_id, $gateway_id ) {
		return $this->sync_gateway_tokens( $tokens, $customer_id, $gateway_id );
	}

	/**
	 * Sync gateway tokens from the Square API
	 * This method will check for existing tokens and then will sync them with the Square API
	 * Any methods which are not found in the Square API will be removed from the tokens
	 *
	 * @param array  $tokens Array of payment tokens
	 * @param int    $user_id User ID
	 * @param string $gateway_id Gateway ID
	 * @param bool   $skip_cache Whether to skip cache
	 * @return array Modified tokens array
	 */
	public function sync_gateway_tokens( $tokens, $user_id, $gateway_id, $skip_cache = false ) {
		if ( ! $this->is_available() ) {
			$this->log_debug( 'Gateway is not available.' );
			return $tokens;
		}

		$supported_gateways = array(
			'fkwcsq_square',
			'square_credit_card',
			'square_plus',
		);

		if ( ! empty( $gateway_id ) && ! in_array( $gateway_id, $supported_gateways, true ) ) {
			$this->log_debug( 'Gateway ID not supported: ' . $gateway_id );
			return $tokens;
		}

		$stored_tokens = array();
		if ( ! empty( $tokens ) ) {
			foreach ( $tokens as $token ) {
				if ( method_exists( $token, 'get_token' ) && ! empty( $token->get_token() ) ) {
					$stored_tokens[ $token->get_token() ] = $token;
				}
			}
		}

		try {
			$payment_methods = $this->get_payment_methods_customer( $user_id, $skip_cache );

			remove_action( 'woocommerce_get_customer_payment_tokens', array( $this, 'maybe_sync_gateway_tokens' ), 8 );

			foreach ( $payment_methods as $payment_method ) {
				if ( ! isset( $payment_method['id'] ) ) {
					continue;
				}

				$token = $this->create_payment_token_from_square_card( $payment_method, $user_id );
				if ( $token ) {
					$tokens[ $token->get_id() ] = $token;

					if ( isset( $stored_tokens[ $token->get_token() ] ) ) {
						unset( $stored_tokens[ $token->get_token() ] );
					}
				}
			}

			if ( ! empty( $tokens ) && ! empty( $gateway_id ) ) {
				foreach ( $tokens as $key => $token ) {
					// Migrate tokens from other Square plugins to our gateway
					if ( in_array( $token->get_gateway_id(), array( 'square_credit_card', 'square_plus' ), true ) ) {
						$token->set_gateway_id( $this->id );
						$token->save();
						$this->log_debug( 'Migrated token from ' . $token->get_gateway_id() . ' to ' . $this->id );
					} elseif ( $this->id !== $token->get_gateway_id() ) {
						unset( $tokens[ $key ] );
					}
				}

				remove_action( 'woocommerce_payment_token_deleted', array( $this, 'detach_customer_token' ), 10, 2 );

				foreach ( $stored_tokens as $token ) {
					unset( $tokens[ $token->get_id() ] );
					$token->delete();
					$this->log_debug( 'Deleted stored token ID: ' . $token->get_id() );
				}
				add_action( 'woocommerce_payment_token_deleted', array( $this, 'detach_customer_token' ), 10, 2 );
			}
			add_action( 'woocommerce_get_customer_payment_tokens', array( $this, 'maybe_sync_gateway_tokens' ), 8, 3 );

		} catch ( \Exception | \Error $e ) {
			$this->log_error( 'Error: ' . $e->getMessage() );
		} finally {
			add_action( 'woocommerce_payment_token_deleted', array( $this, 'detach_customer_token' ), 10, 2 );
			add_action( 'woocommerce_get_customer_payment_tokens', array( $this, 'maybe_sync_gateway_tokens' ), 8, 3 );
		}

		return $tokens;
	}

	/**
	 * Fetch all user tokens from Square API
	 *
	 * @param int  $user_id User ID
	 * @param bool $skip_cache Whether to skip cache
	 * @return array Array of payment methods from Square
	 */
	public function get_payment_methods_customer( $user_id, $skip_cache = false ) {
		if ( ! $user_id ) {
			return array();
		}

		if ( $skip_cache ) {
			$payment_methods = false;
		} else {
			$payment_methods = get_transient( 'fkwcsq_user_tokens_' . $user_id );
			if ( is_array( $payment_methods ) && empty( $payment_methods ) ) {
				$payment_methods = false;
			}
		}

		if ( false === $payment_methods ) {
			$customer_id = get_user_meta( $user_id, '_square_customer_id', true );

			if ( empty( $customer_id ) ) {
				// Check compatibility keys for other Square plugins
				$compatibility_keys = $this->get_compatibility_keys( '_square_customer_id' );
				if ( ! empty( $compatibility_keys ) ) {
					foreach ( $compatibility_keys as $key ) {
						$customer_id = get_user_meta( $user_id, $key, true );
						if ( ! empty( $customer_id ) ) {
							// Save it to our own meta key for future use
							update_user_meta( $user_id, '_square_customer_id', $customer_id );
							$this->log_debug( 'Migrated customer ID from ' . $key . ' to _square_customer_id for user ' . $user_id );
							break;
						}
					}
				}
			}

			if ( empty( $customer_id ) ) {
				$this->log_debug( 'No Square customer ID found for user: ' . $user_id );
				return array();
			}
			$response = $this->api->get_customer_cards( $customer_id );

			if ( is_wp_error( $response ) ) {
				$this->log_error( 'Failed to fetch customer cards: ' . $response->get_error_message() );
				return array();
			}

			if ( ! empty( $response['cards'] ) ) {
				$payment_methods = $response['cards'];
			} else {
				$payment_methods = array();
			}

			set_transient( 'fkwcsq_user_tokens_' . $user_id, $payment_methods, DAY_IN_SECONDS );
		}

		return empty( $payment_methods ) ? array() : $payment_methods;
	}

	/**
	 * Update transient cache with new payment method
	 *
	 * Adds a new payment method to the existing transient cache instead of deleting it,
	 * avoiding unnecessary API calls while keeping the cache up to date.
	 *
	 * @param int   $user_id User ID
	 * @param array $new_card New card data from Square API
	 * @return void
	 */
	private function update_transient_with_new_payment_method( $user_id, $new_card ) {
		if ( ! $user_id || empty( $new_card['id'] ) ) {
			return;
		}

		// Get existing payment methods from transient
		$payment_methods = get_transient( 'fkwcsq_user_tokens_' . $user_id );

		if ( is_array( $payment_methods ) ) {
			$card_exists = false;
			foreach ( $payment_methods as $existing_card ) {
				if ( isset( $existing_card['id'] ) && $existing_card['id'] === $new_card['id'] ) {
					$card_exists = true;
					break;
				}
			}

			if ( ! $card_exists ) {
				$payment_methods[] = $new_card;
				set_transient( 'fkwcsq_user_tokens_' . $user_id, $payment_methods, DAY_IN_SECONDS );
				$this->log_debug( 'Updated transient cache with new payment method for user: ' . $user_id . ' (Total: ' . count( $payment_methods ) . ')' );
			} else {
				$this->log_debug( 'Payment method already exists in transient cache for user: ' . $user_id );
			}
		} else {
			$payment_methods = array( $new_card );
			set_transient( 'fkwcsq_user_tokens_' . $user_id, $payment_methods, DAY_IN_SECONDS );
			$this->log_debug( 'Created transient cache with new payment method for user: ' . $user_id );
		}
	}

	/**
	 * Create payment token from Square card data
	 *
	 * @param array $card_data Square card data
	 * @param int   $user_id User ID
	 * @return WC_Payment_Token_CC|false Created token or false on failure
	 */
	private function create_payment_token_from_square_card( $card_data, $user_id ) {
		try {
			global $wpdb;

			// Check if token already exists in database by token value
			$token_exists = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}woocommerce_payment_tokens where token =%s", $card_data['id'] ), ARRAY_A ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Necessary to check for existing payment tokens, WooCommerce doesn't provide API for this lookup
			if ( ! empty( $token_exists ) ) {
				$token = WC_Payment_Tokens::get( $token_exists[0]['token_id'] );

				$token->set_gateway_id( $this->id );
				$token->save_meta_data();
				$token->save();

				$this->log_debug( 'Updated existing token for Square card: ' . $card_data['id'] );
				return $token;
			}

			$token = new WC_Payment_Token_CC();
			$token->set_token( $card_data['id'] );
			$token->set_gateway_id( $this->id );
			$token->set_card_type( strtolower( $card_data['card_brand'] ) );
			$token->set_last4( $card_data['last_4'] );
			$token->set_expiry_month( $card_data['exp_month'] );
			$token->set_expiry_year( $card_data['exp_year'] );
			$token->set_user_id( $user_id );

			// Store customer ID in token meta
			$customer_id = get_user_meta( $user_id, '_square_customer_id', true );
			if ( $customer_id ) {
				$token->update_meta_data( '_square_customer_id', $customer_id );
			}

			$token->save_meta_data();
			if ( $token->save() ) {
				// Update transient cache with new payment method
				$this->update_transient_with_new_payment_method( $user_id, $card_data );
				$this->log_debug( 'Created payment token for Square card: ' . $card_data['id'] );
				return $token;
			} else {
				$this->log_error( 'Failed to save payment token for Square card: ' . $card_data['id'] );
				return false;
			}
		} catch ( Exception $e ) {
			$this->log_error( 'Error creating payment token: ' . $e->getMessage() );
			return false;
		}
	}

	/**
	 * Detach customer token from Square (disables the card in Square)
	 *
	 * @param int              $token_id Token ID
	 * @param WC_Payment_Token $token Token object
	 */
	public function detach_customer_token( $token_id, $token ) {
		try {
			if ( $token->get_gateway_id() !== $this->id ) {
				return;
			}

			$square_card_id = $token->get_token();
			$response       = $this->api->delete_card( $square_card_id );

			if ( is_wp_error( $response ) ) {
				$this->log_error( 'Failed to disable card in Square: ' . $response->get_error_message() );
			} else {
				$this->log_debug( 'Successfully disabled card in Square: ' . $square_card_id );
			}

			// Clear cache
			$user_id = $token->get_user_id();
			delete_transient( 'fkwcsq_user_tokens_' . $user_id );

		} catch ( Exception $e ) {
			$this->log_error( 'Error detaching customer token: ' . $e->getMessage() );
		}
	}


	/**
	 * Get gateway ID
	 *
	 * @return string
	 */
	public function get_id() {
		return $this->id;
	}

	/**
	 * Check if gateway is enabled
	 *
	 * @return bool
	 */
	public function is_enabled() {
		return 'yes' === $this->enabled;
	}

	/**
	 * Check if gateway supports tokenization
	 *
	 * @return bool
	 */
	public function supports_tokenization() {
		return $this->tokenization;
	}

	/**
	 * Check if gateway supports token editor
	 *
	 * @return bool
	 */
	public function supports_token_editor() {
		return true;
	}

	/**
	 * Check if gateway supports customer ID
	 *
	 * @return bool
	 */
	public function supports_customer_id() {
		return true;
	}

	/**
	 * Get customer ID for user
	 *
	 * @param int   $user_id User ID
	 * @param array $args Additional arguments
	 * @return string|null
	 */
	public function get_customer_id( $user_id, $args = array() ) {
		$customer_id = get_user_meta( $user_id, '_square_customer_id', true );

		if ( empty( $customer_id ) && isset( $args['autocreate'] ) && $args['autocreate'] ) {
			// Auto-create customer if needed
			$order       = $this->create_mock_order_for_user( $user_id );
			$customer_id = $this->api->maybe_create_customer( $order );

			if ( ! is_wp_error( $customer_id ) ) {
				update_user_meta( $user_id, '_square_customer_id', $customer_id );
			} else {
				$customer_id = null;
			}
		}

		return $customer_id;
	}

	/**
	 * Update customer ID for user
	 *
	 * @param int    $user_id User ID
	 * @param string $customer_id Customer ID
	 */
	public function update_customer_id( $user_id, $customer_id ) {
		update_user_meta( $user_id, '_square_customer_id', $customer_id );
	}

	/**
	 * Get customer ID user meta name
	 *
	 * @return string
	 */
	public function get_customer_id_user_meta_name() {
		return '_square_customer_id';
	}

	/**
	 * Get payment tokens handler
	 *
	 * @return \FKWCSQ\Admin\Payment_Token_Editor
	 */
	public function get_payment_tokens_handler() {
		return new \FKWCSQ\Admin\Payment_Token_Editor( $this );
	}

	/**
	 * Create mock order for user
	 *
	 * @param int $user_id User ID
	 * @return \WC_Order
	 */
	private function create_mock_order_for_user( $user_id ) {
		$order = new \WC_Order();

		$order->set_billing_first_name( get_user_meta( $user_id, 'billing_first_name', true ) );
		$order->set_billing_last_name( get_user_meta( $user_id, 'billing_last_name', true ) );
		$billing_email = get_user_meta( $user_id, 'billing_email', true );
		if ( empty( $billing_email ) ) {
			$user = get_userdata( $user_id );
			if ( $user && ! empty( $user->user_email ) ) {
				$billing_email = $user->user_email;
			}
		}
		$order->set_billing_email( $billing_email );
		$order->set_billing_phone( get_user_meta( $user_id, 'billing_phone', true ) );
		$order->set_billing_address_1( get_user_meta( $user_id, 'billing_address_1', true ) );
		$order->set_billing_address_2( get_user_meta( $user_id, 'billing_address_2', true ) );
		$order->set_billing_city( get_user_meta( $user_id, 'billing_city', true ) );
		$order->set_billing_state( get_user_meta( $user_id, 'billing_state', true ) );
		$order->set_billing_postcode( get_user_meta( $user_id, 'billing_postcode', true ) );
		$order->set_billing_country( get_user_meta( $user_id, 'billing_country', true ) );

		$order->set_customer_id( $user_id );

		return $order;
	}

	/**
	 * Get compatibility keys for different Square plugins
	 *
	 * @param string $meta_key The meta key to get compatibility keys for.
	 * @return array Array of compatibility keys.
	 */
	private function get_compatibility_keys( $meta_key ) {
		$config = array(
			'_square_customer_id' => array(
				'wc_square_customer_id',
				'_square_customer_id',
			),
			'_square_source_id'   => array(
				'_square_source_id',
				'_square_payment_method_id',
			),
			'_square_intent_id'   => array(
				'_square_intent_id',
				'_square_payment_id',
			),
		);

		return isset( $config[ $meta_key ] ) ? $config[ $meta_key ] : array();
	}

	/**
	 * Returns whether this user is changing the payment method for a subscription.
	 *
	 * @return bool
	 * @since 5.6.0
	 */
	public function is_changing_payment_method_for_subscription() {
		if ( ! isset( $_GET['change_payment_method'] ) || ! isset( $_GET['_wpnonce'] ) ) {
			return false;
		}

		$subscription_id = sanitize_text_field( wp_unslash( $_GET['change_payment_method'] ) );

		if ( ! is_numeric( $subscription_id ) ) {
			return false;
		}

		$subscription_id = absint( $subscription_id );

		// WooCommerce Subscriptions builds the change-payment-method link with
		// wp_nonce_url() using the default (-1) action (see
		// WC_Subscriptions_Change_Payment_Gateway: the URL is generated and verified
		// with the default action). Verify against that same default action so the
		// legitimate link is accepted; authorization for THIS subscription is enforced
		// by the per-subscription capability check below.
		if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ) ) ) {
			return false;
		}

		if ( $subscription_id > 0 && current_user_can( 'edit_shop_subscription_payment_method', $subscription_id ) ) {
			return wcs_is_subscription( $subscription_id );
		}

		return false;
	}

	/**
	 * Gets saved payment method HTML from a token.
	 *
	 * @since 2.6.0
	 * @param  WC_Payment_Token $token Payment Token.
	 * @return string Generated payment method HTML
	 */
	public function get_saved_payment_method_option_html( $token ) {
		$html = sprintf(
			'<li class="woocommerce-SavedPaymentMethods-token">
				<input id="wc-%1$s-payment-token-%2$s" type="radio" name="wc-%1$s-payment-token" value="%2$s" style="width:auto;" class="woocommerce-SavedPaymentMethods-tokenInput" data-token="%5$s" %4$s />
				<label for="wc-%1$s-payment-token-%2$s">%3$s</label>
			</li>',
			esc_attr( $this->id ),
			esc_attr( $token->get_id() ),
			esc_html( $token->get_display_name() ),
			checked( $token->is_default(), true, false ),
			esc_attr( $token->get_token() )
		);

		/**
		 * Filter the saved payment method HTML.
		 *
		 * @since 2.6.0
		 * @param string $html HTML for the saved payment methods.
		 * @param string $token Token.
		 * @param WC_Payment_Gateway $this Payment gateway instance.
		 * @return string
		 */
		return apply_filters( 'woocommerce_payment_gateway_get_saved_payment_method_option_html', $html, $token, $this );
	}

	/**
	 * Update subscription payment meta when order contains subscriptions
	 *
	 * @param WC_Order $order The order object
	 * @param string   $payment_token Square payment token (card ID)
	 * @param string   $customer_id Square customer ID
	 */
	protected function update_subscription_payment_meta( $order, $payment_token, $customer_id ) {
		// Check if WooCommerce Subscriptions is active
		if ( ! $this->is_subscriptions_enabled() ) {
			return;
		}

		// Check if order contains subscriptions
		if ( ! function_exists( 'wcs_order_contains_subscription' ) || ! wcs_order_contains_subscription( $order ) ) {
			return;
		}

		// Get all subscriptions for this order
		$subscriptions = wcs_get_subscriptions_for_order( $order->get_id(), array( 'order_type' => 'parent' ) );

		if ( empty( $subscriptions ) ) {
			return;
		}
		// Update each subscription with payment token and customer ID
		foreach ( $subscriptions as $subscription ) {
			if ( ! is_a( $subscription, 'WC_Subscription' ) ) {
				continue;
			}

			// Only update if payment method matches
			if ( $subscription->get_payment_method() !== $this->id ) {
				continue;
			}

			$has_changes = false;

			// Update payment token
			if ( ! empty( $payment_token ) ) {
				$current_payment_token = (string) $subscription->get_meta( '_square_payment_token' );
				if ( $current_payment_token !== (string) $payment_token ) {
					$subscription->update_meta_data( '_square_payment_token', $payment_token );
					$has_changes = true;
				}
			}

			// Update customer ID
			if ( ! empty( $customer_id ) ) {
				$current_customer_id = (string) $subscription->get_meta( '_square_customer_id' );
				if ( $current_customer_id !== (string) $customer_id ) {
					$subscription->update_meta_data( '_square_customer_id', $customer_id );
					$has_changes = true;
				}
			}

			// Copy card last4 if available
			$card_last4 = $order->get_meta( '_square_card_last4' );
			if ( ! empty( $card_last4 ) ) {
				$current_card_last4 = (string) $subscription->get_meta( '_square_card_last4' );
				if ( $current_card_last4 !== (string) $card_last4 ) {
					$subscription->update_meta_data( '_square_card_last4', $card_last4 );
					$has_changes = true;
				}
			}

			if ( $has_changes ) {
				$subscription->save();
			}
		}
	}
}
