<?php

namespace Pixeldev\SquareWooSync\Payments;

use Pixeldev\SquareWooSync\Loyalty\LoyaltyProgram;
use Pixeldev\SquareWooSync\Loyalty\LoyaltyRedeeming;
use Pixeldev\SquareWooSync\Payments\Blocks\WC_SquareSync_Gateway_Blocks_Support;
use Pixeldev\SquareWooSync\REST\OrdersController;
use Pixeldev\SquareWooSync\Security\SquareTokenManager;
use Pixeldev\SquareWooSync\Square\SquareHelper;
use WC_Payment_Gateway_CC;  // Changed to extend WC_Payment_Gateway_CC
use WC_Payment_Tokens;
use WP_Error;

require_once plugin_dir_path(__FILE__) . '../../vendor/autoload.php';

// Exit if accessed directly.
if (!defined('ABSPATH')) {
  exit;
}

class WC_SquareSync_Gateway extends WC_Payment_Gateway_CC
{
  private $square_application_id;
  private $square_url;
  private $square_op_mode;
  private $location_id;
  public $page = null;
  public $total_label_suffix;

  public function __construct($paymentId = null, $paymentTitle = null, $paymentDescription = null)
  {
    $settings = get_option('square-woo-sync_settings', []);

    $this->id = 'squaresync_credit';
    $this->icon = '';
    $this->has_fields = true;
    $this->method_title = $paymentTitle ?? 'Square Payments by SquareSync for Woo';
    $this->method_description = $paymentDescription ?? 'Accept payments online using Square. Credit card, Apple Pay, and Google Pay supported';

    // Added 'tokenization' and 'refunds' to supports array
    $this->supports = [
      'products',
      'refunds',
      'tokenization',
      // Add subscription support
      'subscriptions',
      'subscription_cancellation',
      'subscription_suspension',
      'subscription_reactivation',
      'subscription_amount_changes',
      'subscription_date_changes',
      'multiple_subscriptions',
    ];

    $this->init_form_fields();
    $this->init_settings();

    $this->title = $this->get_option('title');
    $this->description = $this->get_option('description');
    $this->enabled = $this->get_option('enabled');
    $this->location_id = $settings['location'] ?? '';

    $hasStoredToken = (bool) SquareTokenManager::get();  // returns false if none

    $isSandbox = isset($settings['environment']) && $settings['environment'] === 'sandbox';

    if ($hasStoredToken) {
      // 1⃣  Use the fixed IDs when a token exists
      $this->square_application_id = $isSandbox
        ? 'sandbox-sq0idb-LMyDEf_itd9_DZukD9RGCQ'
        : 'sq0idp-HD7Og08_uCPjxkaEgoG40Q';
    } else {
      // 2⃣  Otherwise fall back to the user-supplied settings
      $this->square_application_id = $isSandbox
        ? $this->get_option('square_application_id_sandbox')
        : $this->get_option('square_application_id_live');
    }

    $this->square_op_mode = $settings['environment'] ?? 'live';

    $total_label_suffix = apply_filters('woocommerce_square_payment_request_total_label_suffix', __('via WooCommerce', 'squarewoosync-pro'));
    $this->total_label_suffix = $total_label_suffix ? " ($total_label_suffix)" : '';

    add_action('woocommerce_update_options_payment_gateways_' . $this->id, [$this, 'process_admin_options']);
    add_action('wp_enqueue_scripts', [$this, 'enqueue_scripts'], 9);
    add_filter('woocommerce_checkout_fields', [$this, 'remove_credit_card_fields']);
    // Hook for saving the options
    add_action('woocommerce_update_options_payment_gateways_' . $this->id, [$this, 'process_admin_options']);

    add_action('wp_ajax_squaresync_credit_card_get_token_by_id', array($this, 'get_token_by_id'));

    add_action('wp_ajax_nopriv_squaresync_credit_card_get_token_by_id', array($this, 'get_token_by_id'));

    add_action('wc_ajax_square_digital_wallet_get_payment_request', array($this, 'ajax_get_payment_request'));
    add_action('wc_ajax__nopriv_square_digital_wallet_get_payment_request', array($this, 'ajax_get_payment_request'));

    add_action('wp_ajax_get_payment_request', array($this, 'ajax_get_payment_request'));
    add_action('wp_ajax_nopriv_get_payment_request', array($this, 'ajax_get_payment_request'));

    add_action('wc_ajax_square_digital_wallet_recalculate_totals', array($this, 'ajax_recalculate_totals'));
    add_action('wp_ajax_recalculate_totals', array($this, 'ajax_recalculate_totals'));
    add_action('wp_ajax_nopriv_recalculate_totals', array($this, 'ajax_recalculate_totals'));

    add_action('wp_ajax_nopriv_get_needs_shipping', array($this, 'get_needs_shipping'));
    add_action('wp_ajax_get_needs_shipping', array($this, 'get_needs_shipping'));

    // Hook for adding payment methods from 'My Account' page
    add_action('woocommerce_add_payment_method', [$this, 'add_payment_method']);

    // disable auto features when gateway enabled
    add_action('update_option_woocommerce_squaresync_credit_settings', [$this, 'on_square_sync_gateway_enabled'], 10, 2);

    add_action(
      'woocommerce_scheduled_subscription_payment_' . $this->id,
      [$this, 'scheduled_subscription_payment'],
      10,
      2
    );
  }

  /**
   * Charge a scheduled subscription payment.
   *
   * @param float    $amount_to_charge The amount to charge this renewal.
   * @param \WC_Order $renewal_order    The renewal order object.
   */
  public function scheduled_subscription_payment($amount_to_charge, $renewal_order)
  {
    try {
      // 1. Get user and saved tokens
      $user_id = $renewal_order->get_user_id();
      // Get the subscription from the renewal order
      $subscriptions = wcs_get_subscriptions_for_renewal_order($renewal_order->get_id());
      if (empty($subscriptions)) {
        throw new \Exception('No subscriptions found for this renewal order.');
      }

      // Usually one subscription, but handle multiple just in case
      $subscription = reset($subscriptions);

      // Read the token ID from the subscription’s meta
      $token_id = $subscription->get_meta('_payment_method_token');

      if (!$token_id) {
        throw new \Exception('No valid saved token found for subscription renewal.');
      }

      // Then load the token itself
      $payment_token = \WC_Payment_Tokens::get($token_id);

      if (!$payment_token) {
        throw new \Exception('Token object not found in WooCommerce.');
      }

      // 2. Get the Square card ID from the token & the Square customer ID from user meta
      $square_card_id = $payment_token->get_token();
      $square_customer_id = get_user_meta($user_id, 'square_customer_id', true);

      // 3. Convert $amount_to_charge to the smallest currency unit (e.g. cents)
      $ordersController = new OrdersController();
      $currency = $renewal_order->get_currency();
      $multiplier = $ordersController->get_currency_multiplier($currency);
      $total_amount = intval(round($amount_to_charge * $multiplier));

      $ordersController = new OrdersController();
      $locationId = $ordersController->getLocationId($renewal_order);
      // 4. Prepare the body for the Square charge request
      // (Similar to your process_payment logic)
      $payment_data = [
        'idempotency_key' => wp_generate_uuid4(),
        'source_id' => $square_card_id,  // previously saved card ID
        'amount_money' => [
          'amount' => $total_amount,
          'currency' => $currency,
        ],
        'location_id' => $locationId,
        'customer_id' => $square_customer_id,
        'autocomplete' => true,
        'reference_id' => 'Subscription Renewal ' . $renewal_order->get_order_number(),
      ];

      // 5. Send the charge request to Square
      $squareHelper = new SquareHelper();
      $charge_response = $squareHelper->square_api_request('/payments', 'POST', $payment_data, null, false);

      if (empty($charge_response['success']) || false === $charge_response['success']) {
        $error_message = isset($charge_response['error']) ? $charge_response['error'] : 'Square renewal payment failed.';
        throw new \Exception($error_message);
      }

      // 6. Mark the renewal order as paid
      $payment_id = $charge_response['data']['payment']['id'];
      $renewal_order->payment_complete($payment_id);
      $renewal_order->add_order_note(sprintf(
        // translators: 1: formatted renewal amount; 2: Square transaction ID.
        __('Subscription renewal of %1$s via Square succeeded. Transaction ID: %2$s', 'squarewoosync-pro'),
        wc_price($amount_to_charge),
        $payment_id
      ));
    } catch (\Exception $e) {
      // If something failed, mark the order as failed & add a note
      $renewal_order->update_status('failed', sprintf(
        // translators: %s is the error message returned by the exception.
        __('Square renewal failed: %s', 'squarewoosync-pro'),
        $e->getMessage()
      ));
    }
  }

  public function on_square_sync_gateway_enabled($old_value, $new_value)
  {
    if (isset($new_value['enabled']) && $new_value['enabled'] === 'yes' && (!isset($old_value['enabled']) || $old_value['enabled'] !== 'yes')) {
      // Retrieve existing settings or default to an array structure
      $settings = get_option('square-woo-sync_settings', [
        'orders' => [
          'enabled' => true,
          'transactions' => true,
        ],
      ]);

      // Modify the settings
      $settings['orders']['enabled'] = false;
      $settings['orders']['transactions'] = false;

      // Update the option with the new settings
      update_option('square-woo-sync_settings', $settings);
    }
  }

  public function process_admin_options()
  {
    // Call the parent method to process and save the options
    parent::process_admin_options();

    // Now check if square_mode has changed
    $new_square_mode = $this->get_option('square_mode');
    $current_square_mode = get_option('woocommerce_squaresync_credit_square_mode');

    // Compare the new value with the current value
    if ($new_square_mode !== $current_square_mode) {
      // Update the square_mode setting in your custom option
      update_option('woocommerce_squaresync_credit_square_mode', $new_square_mode);

      // Optionally update other settings, such as Square environment
      $settings = get_option('square-woo-sync_settings', []);
      $settings['environment'] = $new_square_mode;
      update_option('square-woo-sync_settings', $settings);
    }
    // Get the new value from the submitted settings form
    $new_square_mode = isset($_POST['woocommerce_squaresync_credit_square_mode']) ? sanitize_text_field($_POST['woocommerce_squaresync_credit_square_mode']) : '';

    // Get the current value from the gateway settings
    $current_square_mode = $this->get_option('square_mode');

    // Compare the new value with the current value
    if ($new_square_mode && $new_square_mode !== $current_square_mode) {
      // Update the square_mode setting
      $this->update_option('square_mode', $new_square_mode);

      // Update other relevant settings if necessary
      $settings = get_option('square-woo-sync_settings', []);
      $settings['environment'] = $new_square_mode;
      update_option('square-woo-sync_settings', $settings);

      // Set the new operation mode
      $this->square_op_mode = $new_square_mode;
    }
  }

  /**
   * Hook for shipping check AJAX
   */
  public function get_needs_shipping()
  {
    if (WC()->cart) {
      $needs_shipping = WC()->cart->needs_shipping();
      wp_send_json_success(['needs_shipping' => $needs_shipping]);
    } else {
      wp_send_json_error('Cart not found');
    }
  }

  public function remove_credit_card_fields($fields)
  {
    unset($fields['billing']['billing_credit_card_number'], $fields['billing']['billing_credit_card_expiry'], $fields['billing']['billing_credit_card_cvc']);
    return $fields;
  }

  public function init_form_fields()
  {
    $settings = get_option('square-woo-sync_settings', []);

    $this->form_fields = [
      'enabled' => [
        'title' => 'Enable/Disable',
        'type' => 'checkbox',
        'label' => 'Enable this payment method',
        'default' => 'no',
      ],
      'title' => [
        'title' => 'Title',
        'type' => 'text',
        'description' => 'Title that the user sees during checkout.',
        'default' => 'Credit Card',
        'desc_tip' => true,
      ],
      'description' => [
        'title' => 'Description',
        'type' => 'textarea',
        'description' => 'Description that the user sees during checkout.',
        'default' => 'Pay securely using your credit card.',
      ],
      'accepted_credit_cards' => [
        'title' => 'Accepted Credit Cards',
        'type' => 'multiselect',
        'options' => [
          'visa' => 'Visa',
          'mastercard' => 'MasterCard',
          'amex' => 'American Express',
          'discover' => 'Discover',
          'jcb' => 'JCB',
          'diners' => 'Diners Club',
          'union' => 'UnionPay',
        ],
        'default' => ['visa', 'mastercard', 'amex', 'discover', 'jcb', 'diners', 'union'],
        'description' => 'Hold control and click to select multiple',
      ],
      // Digital Wallets Section
      'digital_wallets' => [
        'title' => '<legend><h2>Digital Wallets</h2></legend>',
        'type' => 'title',
      ],
      'enable_google_pay' => [
        'title' => 'Enable Google Pay',
        'type' => 'checkbox',
        'label' => 'Enable Google Pay as a payment method',
        'default' => 'no',
      ],
      'enable_apple_pay' => [
        'title' => 'Enable Apple Pay',
        'type' => 'checkbox',
        'label' => 'Enable Apple Pay as a payment method',
        'default' => 'no',
        'description' => 'Apple Pay requires domain authentication. To authorize your domain follow <a href="">this guide.</a>',
      ],
      'enable_after_pay' => [
        'title' => 'Enable Afterpay / Clearpay',
        'type' => 'checkbox',
        'label' => 'Enable Afterpay / Clearpay as a payment method',
        'default' => 'no',
        'description' => 'Ensure your Square account has afterpay enabled. <a href="https://squareup.com/help/us/en/article/7770-accept-in-person-payments-with-afterpay-and-square"> Read guide here</a>',
      ],
      // Square Gift Cards Section
      'square_gift_cards' => [
        'title' => '<legend><h2>Square Gift Cards (PRO ONLY)</h2></legend>',
        'type' => 'title',
      ],
    ];
  }

  public function enqueue_scripts()
  {
    // Always load your shared styles or scripts here
    if ($this->square_op_mode === 'sandbox') {
      $url = 'https://sandbox.web.squarecdn.com/v1/square.js';
    } else {
      $url = 'https://web.squarecdn.com/v1/square.js';
    }

    wp_enqueue_style(
      'wc-square-payments-sdk-css',
      SQUAREWOOSYNC_URL . '/assets/styles/checkout.css',
      array(),
      SQUAREWOOSYNC_VERSION,
      'all'
    );

    wp_enqueue_script(
      'wc-square-payments-sdk',
      $url,
      array(),
      SQUAREWOOSYNC_VERSION,
      true
    );

    // Now check if it’s *actually* a block-based checkout.
    $is_block_checkout = false;

    if (
      function_exists('WC') &&
      method_exists(WC()->checkout, 'is_blocks_checkout') &&
      WC()->checkout->is_blocks_checkout()
    ) {
      $is_block_checkout = true;
    } elseif (defined('WC_BLOCKS_IS_CHECKOUT_PAGE') && WC_BLOCKS_IS_CHECKOUT_PAGE) {
      // Fallback for older versions or blocks plugin usage
      $is_block_checkout = true;
    }

    if (!$is_block_checkout) {
      // Enqueue your "classic"/legacy checkout scripts
      // Use plugin version + filemtime for cache busting to ensure users get latest fixes
      $script_version = SQUAREWOOSYNC_VERSION . '.' . filemtime(SQUAREWOOSYNC_PATH . '/assets/js/utils.js');

      wp_register_script('utils-js', SQUAREWOOSYNC_URL . '/assets/js/utils.js', array('jquery'), $script_version, true);
      wp_register_script('credit-card-js', SQUAREWOOSYNC_URL . '/assets/js/credit-card.js', array('jquery'), $script_version, true);
      // wallets-js depends on utils-js for handler functions (handleShippingOptionChanged, etc.)
      wp_register_script('wallets-js', SQUAREWOOSYNC_URL . '/assets/js/wallets.js', array('jquery', 'utils-js'), $script_version, true);

      wp_enqueue_script('utils-js');
      wp_enqueue_script('credit-card-js');
      wp_enqueue_script('wallets-js');

      wp_enqueue_script(
        'squaresync-legacy',
        SQUAREWOOSYNC_URL . '/assets/js/square-gateway.js',
        null,
        $script_version,
        true
      );

      // Localize script with WooCommerce parameters
      $params = array(
        'applicationId' => $this->square_application_id,
        'locationId' => $this->location_id,
        'applePayEnabled' => $this->get_option('enable_apple_pay'),
        'googlePayEnabled' => $this->get_option('enable_google_pay'),
        'afterPayEnabled' => $this->get_option('enable_after_pay'),
        'cashAppPayEnabled' => $this->get_option('enable_cash_app_pay'),
        'availableCardTypes' => $this->get_option('accepted_credit_cards'),
        'total' => 0,
        'currency' => get_woocommerce_currency(),
        'paymentRequestNonce' => wp_create_nonce('wc-square-get-payment-request'),
        'recalculate_totals_nonce' => wp_create_nonce('wc-square-recalculate-totals-legacy'),
        'context' => $this->get_current_page(),
        'countryCode' => 'AUD',
        'ajax_url' => admin_url('admin-ajax.php'),
        'wc_ajax_url' => \WC_AJAX::get_endpoint('%%endpoint%%'),
      );

      // Add billing data for pay-for-order pages
      if (is_wc_endpoint_url('order-pay')) {
        $order_id = absint(get_query_var('order-pay'));
        $order = wc_get_order($order_id);
        if ($order) {
          $params['orderBillingData'] = array(
            'familyName' => $order->get_billing_last_name(),
            'givenName' => $order->get_billing_first_name(),
            'email' => $order->get_billing_email(),
            'phone' => $order->get_billing_phone(),
            'country' => $order->get_billing_country(),
            'region' => $order->get_billing_state(),
            'city' => $order->get_billing_city(),
            'postalCode' => $order->get_billing_postcode(),
            'addressLines' => array_filter(array(
              $order->get_billing_address_1(),
              $order->get_billing_address_2(),
            )),
          );
        }
      }

      wp_localize_script('utils-js', 'SquareConfig', $params);
      wp_localize_script('squaresync-legacy', 'SquareConfig', $params);
    }
  }

  /**
   * Returns the current page.
   *
   * Stores the result in $this->page to avoid recalculating multiple times per request
   *
   * @since 2.3
   * @return string
   */
  public function get_current_page()
  {
    if (null === $this->page) {
      $is_cart = is_cart() && !WC()->cart->is_empty();
      $is_product = is_product() || wc_post_content_has_shortcode('product_page');
      $this->page = null;

      if ($is_cart) {
        $this->page = 'cart';
      } elseif ($is_product) {
        $this->page = 'product';
      } elseif (is_checkout() || (function_exists('has_block') && has_block('woocommerce/checkout'))) {
        $this->page = 'checkout';
      } elseif (is_account_page()) {
        return 'account';
      }
    }

    return $this->page;
  }

  /**
   * Recalculate shipping methods and cart totals and send updated PaymentRequest JSON.
   *
   * @since 2.3
   * @return void
   */
  public function ajax_recalculate_totals()
  {
    // 1) Try the first nonce, but do NOT kill on failure (3rd param = false).
    check_ajax_referer('wc-square-recalculate-totals', 'security', false);

    // 2) If it's invalid, we fallback to the legacy nonce (normal check).
    if (!wp_verify_nonce($_REQUEST['security'] ?? '', 'wc-square-recalculate-totals')) {
      // This call will kill the request if the legacy nonce is also invalid
      check_ajax_referer('wc-square-recalculate-totals-legacy', 'security');
    }

    if (!WC()->cart) {
      wp_send_json_error(__('Cart not available.', 'squarewoosync-pro'));
      return;
    }

    $chosen_methods = WC()->session->get('chosen_shipping_methods', array());
    $shipping_address = array();
    $payment_request = array();

    $is_pay_for_order_page = isset($_POST['is_pay_for_order_page'])
      ? ('true' === sanitize_text_field(wp_unslash($_POST['is_pay_for_order_page'])))
      : is_wc_endpoint_url('order-pay');

    $order_id = isset($_POST['order_id'])
      ? (int) sanitize_text_field(wp_unslash($_POST['order_id']))
      : absint(get_query_var('order-pay'));

    // We'll only do shipping logic if the cart needs it or we are on a pay-for-order page.
    if (WC()->cart->needs_shipping() || $is_pay_for_order_page) {
      // 1) Possibly parse shipping_contact and recalc shipping.
      if (!empty($_POST['shipping_contact'])) {
        $shipping_contact = wc_clean(wp_unslash($_POST['shipping_contact']));
        $shipping_address = wp_parse_args(
          $shipping_contact,
          array(
            'countryCode' => '',
            'state' => '',
            'city' => '',
            'postalCode' => '',
            'address' => '',
            'address_2' => '',
          )
        );

        // Convert full state name to code if necessary.
        if (!empty($shipping_address['countryCode']) && !empty($shipping_address['state'])) {
          $shipping_address['state'] = self::get_state_code_by_name(
            $shipping_address['countryCode'],
            $shipping_address['state']
          );
        }

        // Recalc shipping using that address.
        $this->calculate_shipping($shipping_address);
      }

      // 2) Possibly parse shipping_option and set chosen shipping method.
      if (!empty($_POST['shipping_option'])) {
        $selected_option = wc_clean(wp_unslash($_POST['shipping_option']));
        $chosen_methods = array($selected_option);
        $this->update_shipping_method($chosen_methods);
      }

      // 3) Gather all shipping packages/rates.
      $packages = WC()->shipping->get_packages();
      $packages = array_values($packages);  // re-index if needed.

      // We want to build an array of shippingOptions.
      $payment_request['shippingOptions'] = array();

      if (!empty($packages)) {
        // Store the user's originally chosen methods & totals so we can restore after the loop.
        $original_chosen_methods = $chosen_methods;
        $original_totals = WC()->cart->get_totals();

        foreach ($packages as $index => $package) {
          if (empty($package['rates'])) {
            continue;
          }

          foreach ($package['rates'] as $method_key => $method) {
            // We want shipping cost + shipping tax for this rate.
            $shipping_cost = (float) $method->cost;
            $shipping_tax = !empty($method->taxes) ? array_sum($method->taxes) : 0.0;

            // Temporarily choose THIS method, recalc totals to see the entire cart total.
            WC()->session->set('chosen_shipping_methods', array($method->id));
            WC()->cart->calculate_totals();

            $recalc_totals = WC()->cart->get_totals();
            $cart_total_for_method = isset($recalc_totals['total'])
              ? (float) $recalc_totals['total']
              : 0.0;

            // Build shipping option structure:
            $payment_request['shippingOptions'][] = array(
              'id' => $method->id,  // e.g., "flat_rate:5"
              'label' => $method->get_label(),  // e.g., "Flat Rate"
              'amount' => number_format($shipping_cost, 2, '.', ''),  // Shipping-only cost
              // Optional shipping tax breakdown
              'taxLineItems' => array(
                array(
                  'id' => 'taxItem1',
                  'label' => 'Taxes',
                  'amount' => number_format($shipping_tax, 2, '.', ''),
                ),
              ),
              // The full cart total IF this method is chosen
              'total' => array(
                'label' => 'Total',
                'amount' => number_format($cart_total_for_method, 2, '.', ''),
              ),
            );
          }
        }

        // Restore the user's original shipping choice & totals
        WC()->session->set('chosen_shipping_methods', $original_chosen_methods);
        WC()->cart->calculate_totals();

        // Reorder so the currently chosen method is first
        $chosen_method_id = !empty($original_chosen_methods[0]) ? $original_chosen_methods[0] : '';
        if ($chosen_method_id) {
          usort($payment_request['shippingOptions'], function ($a, $b) use ($chosen_method_id) {
            if ($a['id'] === $chosen_method_id) {
              return -1;
            }
            if ($b['id'] === $chosen_method_id) {
              return 1;
            }
            return 0;
          });
        }

        // The first shipping option is now the chosen method, store that in session again.
        if (!empty($payment_request['shippingOptions'])) {
          $first_id = $payment_request['shippingOptions'][0]['id'];
          $this->update_shipping_method(array($first_id));
          WC()->cart->calculate_totals();
        }
      }
    } else {
      $payment_request['shippingOptions'] = array();
    }

    // 4) Recalculate totals if not pay_for_order_page.
    if (!$is_pay_for_order_page) {
      WC()->cart->calculate_totals();
    }

    // 5) Build lineItems
    $order_data = array();
    if ($is_pay_for_order_page) {
      $order = wc_get_order($order_id);
      $order_data = array(
        'subtotal' => $order->get_subtotal(),
        'discount' => $order->get_discount_total(),
        'shipping' => $order->get_shipping_total(),
        'fees' => $order->get_total_fees(),
        'taxes' => $order->get_total_tax(),
      );
    }

    $payment_request['lineItems'] = $this->build_payment_request_line_items($order_data);

    // 6) Build total — i.e., the final cart total with the user’s *actual* chosen shipping method.
    if ($is_pay_for_order_page) {
      $total_amount = (float) wc_get_order($order_id)->get_total();
    } else {
      $total_amount = (float) WC()->cart->total;  // or get_totals()['total']
    }

    $payment_request['total'] = array(
      'label' => get_bloginfo('name', 'display') . esc_html($this->total_label_suffix),
      'amount' => number_format($total_amount, 2, '.', ''),
      'pending' => false,
    );

    wp_send_json_success($payment_request);
  }

  /**
   * Returns location's state code by state name.
   *
   * @param string $country_code The country's 2 letter ISO 3166-1 alpha-2 code.
   * @param string $state_name   The full name of the state that is to be search for its code.
   *
   * @return string
   */
  public static function get_state_code_by_name($country_code = '', $state_name = '')
  {
    if (empty($country_code) || empty($state_name)) {
      return '';
    }

    $states = WC()->countries->get_states($country_code);

    /**
     * Check for valid country code that don't have list of states,
     * return state code as it is.
     */
    $countries = WC()->countries->get_countries();

    if (false === $states && isset($countries[$country_code])) {
      return $state_name;
    }

    if (is_array($states)) {
      /** Return the state code if $state_name already contains a valid state code. */
      if (isset($states[$state_name])) {
        return $state_name;
      }

      foreach ($states as $code => $name) {
        if ($name === $state_name) {
          return $code;
        }
      }
    }

    return '';
  }

  /**
   * Reset shipping and calculate the latest shipping options/package with the given address.
   *
   * If no address, use the store's base address as default.
   *
   * @since 2.3
   * @param array $address
   * @return void
   */
  public function calculate_shipping($address = array())
  {
    if (!WC()->cart) {
      throw new \Exception('Cart not available.');
    }

    WC()->shipping->reset_shipping();

    if ($address['countryCode']) {
      WC()->customer->set_location(strtoupper($address['countryCode']), $address['state'], $address['postalCode'], $address['city']);
      WC()->customer->set_shipping_location(strtoupper($address['countryCode']), $address['state'], $address['postalCode'], $address['city']);
    } else {
      WC()->customer->set_billing_address_to_base();
      WC()->customer->set_shipping_address_to_base();
    }

    WC()->customer->set_calculated_shipping(true);
    WC()->customer->save();

    $packages = array();
    $packages[0]['contents'] = WC()->cart->get_cart();
    $packages[0]['contents_cost'] = 0;
    $packages[0]['applied_coupons'] = WC()->cart->applied_coupons;
    $packages[0]['user']['ID'] = get_current_user_id();
    $packages[0]['destination']['country'] = $address['countryCode'];
    $packages[0]['destination']['state'] = $address['state'];
    $packages[0]['destination']['postcode'] = $address['postalCode'];
    $packages[0]['destination']['city'] = $address['city'];
    $packages[0]['destination']['address'] = $address['address'];
    $packages[0]['destination']['address_2'] = $address['address_2'];

    foreach (WC()->cart->get_cart() as $item) {
      if ($item['data']->needs_shipping()) {
        if (isset($item['line_total'])) {
          $packages[0]['contents_cost'] += $item['line_total'];
        }
      }
    }

    /**
     * Hook to filter shipping packages.
     *
     * @param array Array of shipping packages.
     * @since 2.3
     */
    $packages = apply_filters('woocommerce_cart_shipping_packages', $packages);

    WC()->shipping->calculate_shipping($packages);
  }

  /**
   * Updates shipping method in WC session
   *
   * @since 2.3
   * @param array $shipping_methods Array of selected shipping methods ids
   * @return void
   */
  public function update_shipping_method($shipping_methods)
  {
    $chosen_shipping_methods = WC()->session->get('chosen_shipping_methods');

    if (is_array($shipping_methods)) {
      foreach ($shipping_methods as $i => $value) {
        $chosen_shipping_methods[$i] = wc_clean($value);
      }
    }

    WC()->session->set('chosen_shipping_methods', $chosen_shipping_methods);
  }

  /**
   * Get the payment request object in an ajax request
   *
   * @since 2.3
   * @return void
   */
  public function ajax_get_payment_request()
  {
    check_ajax_referer('wc-square-get-payment-request', 'security');

    $payment_request = array();
    $context = !empty($_POST['context']) ? wc_clean(wp_unslash($_POST['context'])) : '';

    try {
      if ('product' === $context) {
        $product_id = !empty($_POST['product_id']) ? wc_clean(wp_unslash($_POST['product_id'])) : 0;
        $quantity = !empty($_POST['quantity']) ? wc_clean(wp_unslash($_POST['quantity'])) : 1;
        $attributes = !empty($_POST['attributes']) ? wc_clean(wp_unslash($_POST['attributes'])) : array();

        try {
          $payment_request = $this->get_product_payment_request($product_id, $quantity, $attributes);
        } catch (\Exception $e) {
          wp_send_json_error($e->getMessage());
        }
      } else {
        $payment_request = $this->get_payment_request_for_context($context);
      }

      if (empty($payment_request)) {
        /* translators: Context (product, cart, checkout or page) */
        throw new \Exception(sprintf(esc_html__('Empty payment request data for %s.', 'squarewoosync-pro'), !empty($context) ? $context : 'page'));
      }
    } catch (\Exception $e) {
      wp_send_json_error($e->getMessage());
    }

    wp_send_json_success(wp_json_encode($payment_request));
  }

  /**
   * Build the payment request object for the given context (i.e. product, cart or checkout page)
   *
   * Payment request objects are used by the Payments and need to be in a specific format.
   * Reference: https://developer.squareup.com/docs/api/paymentform#paymentform-paymentrequestobjects
   *
   * @since 2.3
   * @param string $context
   * @return array
   */
  public function get_payment_request_for_context($context)
  {
    // Ignoring nonce verification checks as it is already handled in the parent function.
    $payment_request = array();

    $is_pay_for_order_page = isset($_POST['is_pay_for_order_page']) ? 'true' === sanitize_text_field(wp_unslash($_POST['is_pay_for_order_page'])) : is_wc_endpoint_url('order-pay');  // phpcs:ignore WordPress.Security.NonceVerification.Missing
    $order_id = isset($_POST['order_id']) ? (int) sanitize_text_field(wp_unslash($_POST['order_id'])) : absint(get_query_var('order-pay'));  // phpcs:ignore WordPress.Security.NonceVerification.Missing

    switch ($context) {
      case 'product':
        try {
          $payment_request = $this->get_product_payment_request(get_the_ID());
        } catch (\Exception $e) {
          error_log($e);
        }
        break;

      case 'cart':
      case 'checkout':
        if (is_wc_endpoint_url('order-pay') || $is_pay_for_order_page) {
          $order = wc_get_order($order_id);
          $payment_request = $this->build_payment_request(
            $order->get_total(),
            array(
              'order_id' => $order_id,
              'is_pay_for_order_page' => $is_pay_for_order_page,
            )
          );
        } elseif (isset(WC()->cart)) {
          WC()->cart->calculate_totals();
          $payment_request = $this->build_payment_request(WC()->cart->total);
        }

        break;
      case 'account':
        $user_id = get_current_user_id();
        if ($user_id) {
          $billing_info = array(
            'billing_address_1' => get_user_meta($user_id, 'billing_address_1', true),
            'billing_address_2' => get_user_meta($user_id, 'billing_address_2', true),
            'billing_city' => get_user_meta($user_id, 'billing_city', true),
            'billing_state' => get_user_meta($user_id, 'billing_state', true),
            'billing_postcode' => get_user_meta($user_id, 'billing_postcode', true),
            'billing_country' => get_user_meta($user_id, 'billing_country', true),
          );
          // Pass $0.01 as the amount with no additional line items or shipping options.
          $payment_request = $this->build_payment_request(0.01, array('billing_info' => $billing_info, 'context' => 'account'));
        } else {
          throw new \Exception(__('Unable to retrieve customer billing information.', 'squarewoosync-pro'));
        }
        break;
    }

    return $payment_request;
  }

  /**
   * Checks the cart to see if Square Digital Wallets is allowed to purchase all cart items.
   *
   * @since 2.3
   * @return bool
   */
  public function allowed_for_cart()
  {
    if (!WC()->cart) {
      throw new \Exception('Cart not available.');
    }
    foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item) {
      /**
       * Hook to filter cart item product.
       *
       * @param array  $cart_item['data] Product object.
       * @param array  $cart_item        Cart item.
       * @param string $cart_item_key    Cart item key.
       * @since 2.3
       */
      $_product = apply_filters('woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key);

      if (!in_array($_product->get_type(), $this->supported_product_types(), true)) {
        return false;
      }

      // Trial subscriptions with shipping are not supported
      if (class_exists('WC_Subscriptions_Cart') && class_exists('WC_Subscriptions_Product') && \WC_Subscriptions_Cart::cart_contains_subscription() && $_product->needs_shipping() && \WC_Subscriptions_Product::get_trial_length($_product) > 0) {
        return false;
      }

      // Pre Orders compatibility where we don't support charge upon release.
      if (class_exists('WC_Pre_Orders_Cart') && class_exists('WC_Pre_Orders_Product') && \WC_Pre_Orders_Cart::cart_contains_pre_order() && \WC_Pre_Orders_Product::product_is_charged_upon_release(\WC_Pre_Orders_Cart::get_pre_order_product())) {
        return false;
      }
    }

    return true;
  }

  /**
   * Returns a list the supported product types that can be used to purchase a digital wallet
   *
   * @since 2.3
   * @return array
   */
  public function supported_product_types()
  {
    /**
     * Hook to filter array of post types that can support digital wallets.
     *
     * @param array Array of supported post types.
     * @since 2.3
     */
    return apply_filters(
      'wc_square_digital_wallets_supported_product_types',
      array(
        'simple',
        'variable',
        'variation',
        'booking',
        'bundle',
        'composite',
        'mix-and-match',
      )
    );
  }

  /**
   * Build a payment request object to be sent to Payments on the product page
   *
   * Documentation: https://developer.squareup.com/docs/api/paymentform#paymentform-paymentrequestobjects
   *
   * @since 2.3
   * @param int $product_id
   * @param bool $add_to_cart - whether or not the product needs to be added to the cart before building the payment request
   * @return array
   */
  public function get_product_payment_request($product_id = 0, $quantity = 1, $attributes = array(), $add_to_cart = false)
  {
    $data = array();
    $items = array();
    $product_id = !empty($product_id) ? $product_id : get_the_ID();
    $product = wc_get_product($product_id);
    $variation_id = 0;

    if (!is_a($product, 'WC_Product')) {
      /* translators: product ID */
      throw new \Exception(sprintf(esc_html__('Product with the ID (%d) cannot be found.', 'squarewoosync-pro'), absint($product_id)));
    }

    $quantity = $product->is_sold_individually() ? 1 : $quantity;

    if ('variable' === $product->get_type() && !empty($attributes)) {
      $data_store = \WC_Data_Store::load('product');
      $variation_id = $data_store->find_matching_product_variation($product, $attributes);

      if (!empty($variation_id)) {
        $product = wc_get_product($variation_id);
      }
    }

    if (!$product->has_enough_stock($quantity)) {
      /* translators: 1: product name 2: quantity in stock */
      throw new \Exception(sprintf(esc_html__('You cannot add that amount of "%1$s"; to the cart because there is not enough stock (%2$s remaining).', 'squarewoosync-pro'), esc_html($product->get_name()), esc_html(wc_format_stock_quantity_for_display($product->get_stock_quantity(), $product))));
    }

    if (!$product->is_purchasable()) {
      /* translators: 1: product name */
      throw new \Exception(sprintf(esc_html__('You cannot purchase "%1$s" because it is currently not available.', 'squarewoosync-pro'), esc_html($product->get_name())));
    }

    if ($add_to_cart) {
      WC()->cart->empty_cart();
      WC()->cart->add_to_cart($product->get_id(), $quantity, $variation_id, $attributes);

      WC()->cart->calculate_totals();
      return $this->build_payment_request(WC()->cart->total);
    }

    $amount = number_format($quantity * $product->get_price(), 2, '.', '');
    $quantity_label = 1 < $quantity ? ' x ' . $quantity : '';

    $items[] = array(
      'label' => $product->get_name() . $quantity_label,
      'amount' => $amount,
      'pending' => false,
    );

    if (wc_tax_enabled()) {
      $items[] = array(
        'label' => __('Tax', 'squarewoosync-pro'),
        'amount' => '0.00',
        'pending' => false,
      );
    }

    $data['requestShippingContact'] = $product->needs_shipping();
    $data['lineItems'] = $items;

    return $this->build_payment_request($amount, $data);
  }

  /**
   * Build the PaymentRequest object that includes shipping, line items, and the grand total.
   *
   * @param array $data Additional data controlling how the request is built.
   * @return array
   * @throws \Exception
   */
  public function build_payment_request($data = [])
  {
    if (!WC()->cart) {
      throw new \Exception('Cart not available.');
    }

    $is_pay_for_order_page = !empty($data['is_pay_for_order_page']) ? $data['is_pay_for_order_page'] : false;
    $order_id = !empty($data['order_id']) ? $data['order_id'] : 0;

    // Check if shipping is needed.
    $request_shipping_address = false;
    if (!$is_pay_for_order_page) {
      $request_shipping_address = WC()->cart->needs_shipping();
    }

    // Base country & currency
    $default_country = get_option('woocommerce_default_country', 'AU');
    $country_bits = explode(':', $default_country);
    $country_only = strtoupper($country_bits[0]);
    $currency_code = get_woocommerce_currency() ?: 'AUD';

    // Merge defaults.
    $data = wp_parse_args(
      $data,
      [
        // For Afterpay, Apple Pay, Google Pay, etc.
        'requestShippingAddress' => $request_shipping_address,
        'requestShippingContact' => $request_shipping_address,
        'requestEmailAddress' => true,
        'requestBillingContact' => true,
        'countryCode' => $country_only,
        'currencyCode' => $currency_code,
      ]
    );

    // If shipping is needed, build out shipping options, each with:
    //  - 'amount' => Just the shipping cost
    //  - 'total.amount' => The entire cart total if that shipping method is selected
    if ($data['requestShippingAddress']) {
      $shipping_options = [];

      // Store original shipping method selection & totals so we can restore it
      $original_chosen_methods = WC()->session->get('chosen_shipping_methods');
      $original_cart_totals = WC()->cart->get_totals();

      $packages = WC()->shipping->get_packages();

      if (!empty($packages[0]['rates'])) {
        foreach ($packages[0]['rates'] as $method) {
          // Shipping cost & taxes for this method
          $shipping_cost = (float) $method->cost;
          $shipping_tax = !empty($method->taxes) ? array_sum($method->taxes) : 0;

          // Temporarily set this shipping method, then force WooCommerce
          // to recalc totals so we know the entire cart total with this method.
          WC()->session->set('chosen_shipping_methods', [$method->id]);
          WC()->cart->calculate_totals();

          // Grab the newly computed total
          $recalc_totals = WC()->cart->get_totals();
          $cart_total_for_method = isset($recalc_totals['total']) ? (float) $recalc_totals['total'] : 0.0;

          // Build the shipping option array
          $shipping_options[] = [
            'id' => $method->id,  // e.g. "flat_rate:1"
            'label' => $method->get_label(),
            'amount' => number_format($shipping_cost, 2, '.', ''),  // shipping-only cost
            // Optionally show shipping tax:
            'taxLineItems' => [
              [
                'id' => 'taxItem1',
                'label' => 'Taxes',
                'amount' => number_format($shipping_tax, 2, '.', ''),
              ],
            ],
            // Show the total cart price if this shipping method is selected
            'total' => [
              'label' => 'Total',
              'amount' => number_format($cart_total_for_method, 2, '.', ''),
            ],
          ];
        }
      }

      // Restore the original shipping method & recalc
      WC()->session->set('chosen_shipping_methods', $original_chosen_methods);
      WC()->cart->calculate_totals();

      // Sort chosen shipping method to the top if you wish
      if (!empty($original_chosen_methods[0])) {
        usort($shipping_options, function ($a, $b) use ($original_chosen_methods) {
          return ($a['id'] === $original_chosen_methods[0]) ? -1 : 1;
        });
      }

      $data['shippingOptions'] = $shipping_options;
    }

    // Now that we've restored the original method, get the final cart total
    // which includes items, shipping, taxes, fees, discounts, etc.
    $restored_totals = WC()->cart->get_totals();
    $final_cart_total = isset($restored_totals['total']) ? (float) $restored_totals['total'] : 0.0;

    // Build the top-level PaymentRequest total
    $data['total'] = [
      // E.g. "Your Site — Total"
      'label' => get_bloginfo('name', 'display') . $this->total_label_suffix,
      'amount' => number_format($final_cart_total, 2, '.', ''),
      'pending' => false,
    ];

    // Optionally, build line items from cart or order details
    $data['lineItems'] = $this->build_payment_request_line_items();

    return $data;
  }

  /**
   * Returns cart totals in an array format
   *
   * @since 2.3
   * @throws \Exception if no cart is found
   * @return array
   */
  public function get_cart_totals()
  {
    if (!isset(WC()->cart)) {
      throw new \Exception('Cart data cannot be found.');
    }

    return array(
      'subtotal' => WC()->cart->subtotal_ex_tax,
      'discount' => WC()->cart->get_cart_discount_total(),
      'shipping' => WC()->cart->shipping_total,
      'fees' => WC()->cart->fee_total,
      'taxes' => WC()->cart->tax_total + WC()->cart->shipping_tax_total,
    );
  }

  public function build_payment_request_line_items($totals = array())
  {
    // If no totals are provided, get them from the cart.
    $totals = empty($totals) ? $this->get_cart_totals() : $totals;
    $line_items = array();
    $order_id = isset($_POST['order_id']) ? (int) sanitize_text_field(wp_unslash($_POST['order_id'])) : absint(get_query_var('order-pay'));  // phpcs:ignore WordPress.Security.NonceVerification.Missing

    // Determine whether we are working with an order or the current cart
    if ($order_id) {
      $order = wc_get_order($order_id);
      $iterable = $order->get_items();
    } else {
      $iterable = WC()->cart->get_cart();
    }

    // Iterate through the items and build the line items array
    foreach ($iterable as $item) {
      $quantity = $order_id ? $item->get_quantity() : $item['quantity'];
      $amount = $order_id ? $item->get_total() : $item['line_total'];

      // Add a line item for each product
      $line_items[] = array(
        'label' => $order_id ? $item->get_name() : $item['data']->get_name(),
        'amount' => number_format($amount, 2, '.', ''),
        'pending' => false,
      );
    }

    // Add shipping line item if applicable
    if (isset($totals['shipping'])) {
      $line_items[] = array(
        'label' => __('Shipping', 'squarewoosync-pro'),
        'amount' => number_format($totals['shipping'], 2, '.', ''),
        'pending' => false,
      );
    }

    // Add tax line item if applicable
    if (isset($totals['taxes']) && $totals['taxes'] > 0) {
      $line_items[] = array(
        'label' => __('Tax', 'squarewoosync-pro'),
        'amount' => number_format($totals['taxes'], 2, '.', ''),
        'pending' => false,
      );
    }

    // Add discount line item if applicable
    if (isset($totals['discount']) && $totals['discount'] > 0) {
      $line_items[] = array(
        'label' => __('Discount', 'squarewoosync-pro'),
        'amount' => '-' . number_format(abs($totals['discount']), 2, '.', ''),  // Ensure discount is negative
        'pending' => false,
      );
    }

    // Add fees line item if applicable
    if (isset($totals['fees']) && $totals['fees'] > 0) {
      $line_items[] = array(
        'label' => __('Fees', 'squarewoosync-pro'),
        'amount' => number_format($totals['fees'], 2, '.', ''),
        'pending' => false,
      );
    }

    return $line_items;
  }

  /**
   * Ajax callback to return payment token by token ID.
   *
   * @since 4.2.0
   */
  public function get_token_by_id()
  {
    $nonce = isset($_GET['nonce']) ? sanitize_text_field(wp_unslash($_GET['nonce'])) : false;

    if (!wp_verify_nonce($nonce, 'payment_token_nonce')) {
      wp_send_json_error(esc_html__('Nonce verification failed.', 'squarewoosync-pro'));
    }

    $token_id = isset($_GET['token_id']) ? absint(wp_unslash($_GET['token_id'])) : false;

    if (!$token_id) {
      wp_send_json_error(esc_html__('Token ID missing.', 'squarewoosync-pro'));
    }

    $token_obj = \WC_Payment_Tokens::get($token_id);

    if (is_null($token_obj)) {
      wp_send_json_error(esc_html__('No payment token exists for this ID.', 'squarewoosync-pro'));
    }

    wp_send_json_success($token_obj->get_token());
  }

  public function payment_fields()
  {
    // Check if tokenization is supported and the user is logged in
    if ($this->supports('tokenization') && is_user_logged_in()) {
      $user_id = get_current_user_id();
      $tokens = \WC_Payment_Tokens::get_customer_tokens($user_id, $this->id);

      if (!empty($tokens)) {
        if (!is_account_page()) {
          $this->saved_payment_methods();
        }
      }
    }

    if (is_account_page()) {
      // Render Add Payment Method form on My Account page
      $this->render_add_payment_method_form();
    } else {
      // Render the credit card fields on Checkout page
      $this->render_checkout_payment_form();
      // Display the 'Save payment method' checkbox only on Checkout page
      if (
        !class_exists('WC_Subscriptions_Cart') ||
        !\WC_Subscriptions_Cart::cart_contains_subscription()
      ) {
        if ($this->supports('tokenization') && is_user_logged_in()) {
          $this->save_payment_method_checkbox();
        }
      }
    }
  }

  /**
   * Render the Add Payment Method form on My Account page.
   */
  private function render_add_payment_method_form()
  {
    $nonce_sec = wp_create_nonce('sws_add_payment_method');

?>
    <form id="add-payment-form">
      <input type="hidden" name="nonce_sec" value="<?php echo esc_attr($nonce_sec); ?>">
      <div id="square-credit-card-fields">
        <div class="sws-legacy-wallets" style="display: none;">
          <div id="sws-gpay-legacy" style="display: none;"></div>
          <div id="sws-applepay-legacy" class="sws-applepay-btn sws-wallet-btn" role="button" style="height: 40px; display: none;">
            <span class="text"></span>
            <span class="logo"></span>
          </div>
          <div id="sws-cashapp-legacy" style="display: none;"></div>
        </div>

        <div id="card-container"></div>
      </div>

      <div id="payment-loader" style="display: none;">
        <div class="loader">Verifying, please wait...</div>
      </div>
      <div style="color: red;" id="payment-status-container"></div>
    </form>
  <?php
  }

  /**
   * Render the Checkout Payment Form.
   */
  private function render_checkout_payment_form()
  {
  ?>
    <form id="payment-form">
      <div id="gift-card-container"></div>
      <input type="hidden" id="squaresync_gift_card_nonce" name="squaresync_gift_card_nonce" value="">


      <div class="sws-legacy-wallets" style="display: none;">
        <div id="sws-afterpay-legacy" style="display: none;"></div>
        <div id="sws-gpay-legacy" style="display: none;"></div>
        <div id="sws-applepay-legacy" class="sws-applepay-btn sws-wallet-btn" role="button" style="height: 40px; display: none;">
          <span class="text"></span>
          <span class="logo"></span>
        </div>
        <div id="sws-cashapp-legacy" style="display: none;"></div>
      </div>

      <div id="card-container"></div>
    </form>
    <div id="payment-loader" style="display: none;">
      <div class="loader">Verifying, please wait...</div>
    </div>
    <div style="color: red;" id="payment-status-container"></div>
<?php
  }

  public function process_payment($order_id)
  {
    error_log("[SquareSync Gateway] Starting payment processing for Order #{$order_id}");

    try {
      $order = wc_get_order($order_id);
      $settings = get_option('square-woo-sync_settings', []);

      error_log("[SquareSync Gateway] Order #{$order_id}: Order object retrieved, total: " . $order->get_total());

      // Validate pickup date/time if required
      $order_settings = $settings['orders'] ?? [];
      if (
        isset($order_settings['enablePickupDateTime']) &&
        $order_settings['enablePickupDateTime'] === true &&
        isset($order_settings['requirePickupDateTime']) &&
        $order_settings['requirePickupDateTime'] === true
      ) {
        // Check if this is a pickup order
        $shipping_methods = $order->get_shipping_methods();
        $pickup_methods = $order_settings['pickupMethod'] ?? [];

        // Ensure pickup_methods is an array
        if (!is_array($pickup_methods)) {
          $pickup_methods = !empty($pickup_methods) ? [$pickup_methods] : [];
        }

        foreach ($shipping_methods as $shipping_method) {
          $method_id = $shipping_method->get_method_id();

          // Check if this shipping method is a pickup method
          $is_pickup = false;
          foreach ($pickup_methods as $pickup_method) {
            $pickup_method_id = explode(':', $pickup_method)[0];
            if ($method_id === $pickup_method_id) {
              $is_pickup = true;
              break;
            }
          }

          if ($is_pickup) {
            // This is a pickup order - validate that date/time are set
            $pickup_date = WC()->session->get('pickup_date', '');
            $pickup_time = WC()->session->get('pickup_time', '');

            if (empty($pickup_date) || empty($pickup_time)) {
              wc_add_notice(
                __('Please select a pickup date and time before completing your order.', 'squarewoosync-pro'),
                'error'
              );
              return [
                'result' => 'failure',
                'redirect' => ''
              ];
            }

            // Date and time are valid, proceed
            break;
          }
        }
      }

      $squareHelper = new SquareHelper();
      $ordersController = new OrdersController();
      $multiplier = $ordersController->get_currency_multiplier($order->get_currency());
      $user_id = $order->get_user_id();
      $locationId = $ordersController->getLocationId($order);

      // 1) Check for an existing Gift Card in session
      $gift_card_id = WC()->session->get('applied_gift_card_id', '');
      $gift_card_amount = (float) WC()->session->get('applied_gift_card_amount', 0);
      $gift_card_amount_cents = intval(round($gift_card_amount * $multiplier));

      // 2) Payment token from POST if using a saved card or new token
      $token_id = isset($_POST['wc-' . $this->id . '-payment-token'])
        ? wc_clean($_POST['wc-' . $this->id . '-payment-token'])
        : '';

      /**
       * ------------------------------------------------
       * FORCE TOKENIZATION IF ORDER CONTAINS SUBSCRIPTION
       * ------------------------------------------------
       */
      if (
        class_exists('WC_Subscriptions') &&
        wcs_order_contains_subscription($order)  // If the order has a subscription
      ) {
        // If they're NOT using an existing saved token (i.e. $token_id = '' or 'new'),
        // force "save payment method" so that a new token is created.
        if (empty($token_id) || 'new' === $token_id) {
          $_POST['wc-' . $this->id . '-new-payment-method'] = 'true';
          $_POST['wc-squaresync_credit-new-payment-method'] = '1';
        }
      }

      // Gather potential tokens from POST
      $square_verification_token = sanitize_text_field(
        $_POST['square_verification_token']
          ?? ($_POST['wc-squaresync_credit-buyer-verification-token'] ?? '')
      );
      $square_payment_token = sanitize_text_field(
        $_POST['square_payment_token']
          ?? ($_POST['wc-squaresync_credit-payment-nonce'] ?? '')
      );

      // Debug logs removed - wallet payment processing

      // We'll keep a reference to the WC_Payment_Token_CC object if it exists
      $payment_token = null;
      $square_token = '';

      // 3) Determine if order total is > 0
      $total_amount = intval(round($order->get_total() * $multiplier));
      $currency = $order->get_currency();

      // If user chose an existing saved token, load it
      if ($token_id && $token_id !== 'new') {
        $payment_token = \WC_Payment_Tokens::get($token_id);

        if (!$payment_token || $payment_token->get_user_id() !== get_current_user_id()) {
          wc_add_notice(__('Invalid payment method. Please try again.', 'squarewoosync-pro'), 'error');
          return;
        }
        // The actual Square card ID (e.g. ccof:xxxx)
        $square_token = $payment_token->get_token();
      } else {
        // New payment method with square_payment_token
        $square_token = $square_payment_token;
        if (empty($square_token) && $total_amount > 0) {
          // If we have a total > 0 but no token, that's an error
          return $this->handle_error($order_id, 'Payment token is missing.');
        }
      }

      // 4) Retrieve or create the Square customer ID
      error_log("[SquareSync Gateway] Order #{$order_id}: Retrieving or creating Square customer");
      $square_customer_id = $ordersController->getOrCreateSquareCustomer($order, $squareHelper);
      if (!$square_customer_id) {
        error_log("[SquareSync Gateway] WARNING: Square customer ID not available for Order #{$order_id}");
      } else {
        error_log("[SquareSync Gateway] Order #{$order_id}: Square customer ID: {$square_customer_id}");
      }
      if ($user_id) {
        update_user_meta($user_id, 'square_customer_id', $square_customer_id);
      }

      // 5) Check if order splitting is enabled and applicable
      $split_orders_enabled = !empty($settings['orders']['splitByProductLocations']);

      // Check if this is a local pickup order - if so, disable splitting
      $is_pickup_order = false;
      if ($split_orders_enabled) {
        $shipping_methods = $order->get_shipping_methods();
        $pickup_methods = $settings['orders']['pickupMethod'] ?? [];

        // Ensure pickup_methods is an array
        if (!is_array($pickup_methods)) {
          $pickup_methods = !empty($pickup_methods) ? [$pickup_methods] : [];
        }

        foreach ($shipping_methods as $shipping_method) {
          $method_id = $shipping_method->get_method_id();

          // Check if this shipping method is a pickup method
          foreach ($pickup_methods as $pickup_method) {
            $pickup_method_id = explode(':', $pickup_method)[0];
            if ($method_id === $pickup_method_id) {
              $is_pickup_order = true;
              break 2; // Break out of both loops
            }
          }
        }

        // Disable splitting for pickup orders
        if ($is_pickup_order) {
          $split_orders_enabled = false;
          error_log("Order #{$order_id}: Local pickup detected. Disabling order splitting.");
        }
      }

      $square_order_response = null;

      if ($split_orders_enabled) {
        // SPLIT ORDER MODE: Take payment first, then queue background job
        // This allows checkout to complete quickly without waiting for inventory checks
        error_log("[SquareSync Gateway] Order #{$order_id}: SPLIT ORDER MODE enabled");

        // Store pending payment metadata for background job
        $order->update_meta_data('_square_payment_id_pending', 'PENDING');
        $order->update_meta_data('_square_order_pending_split', true);
        $order->save();

        // Skip creating Square order here - will be done in background
        error_log("[SquareSync Gateway] Order #{$order_id}: Square order creation deferred to background job");
      } else {
        // NORMAL MODE: Create Square order immediately
        error_log("[SquareSync Gateway] Order #{$order_id}: NORMAL MODE - Creating Square order immediately");
        $square_order_response = $this->attempt_create_square_order(
          $ordersController,
          $order,
          $square_customer_id,
          $squareHelper,
          $order_id,
          $locationId
        );
        if (!$square_order_response) {
          error_log("[SquareSync Gateway] WARNING: Square order could not be created for Order #{$order_id}");
        } else {
          error_log("[SquareSync Gateway] Order #{$order_id}: Square order created successfully");
        }
      }

      /**
       * ----------------
       * LOYALTY logic
       * ----------------
       */
      $loyalty_enabled = isset($settings['loyalty']['enabled']) ? $settings['loyalty']['enabled'] : false;
      $loyalty_account_id = WC()->session->get('loyalty_account_id');
      $reward_tier_id = WC()->session->get('reward_tier_id');
      $cart_fees = WC()->cart->get_fees();
      $redeeming_rewards = false;

      foreach ($cart_fees as $fee) {
        if (isset($fee->name) && $fee->name === 'Loyalty Discount') {
          $redeeming_rewards = true;
          break;
        }
      }

      // Only process loyalty if the class exists (feature may not be available)
      if (!class_exists('Pixeldev\\SquareWooSync\\Loyalty\\LoyaltyRedeeming')) {
        $redeeming_rewards = false;
      }

      // If the loyalty discount fee is applied and we have account + tier
      if ($redeeming_rewards && $loyalty_account_id && $reward_tier_id) {
        $loyaltyRedeeming = new LoyaltyRedeeming();
        if (isset($square_order_response['data']['order']['id'])) {
          // Redeem loyalty points
          $redeemed = $loyaltyRedeeming->redeem_loyalty_reward(
            $square_order_response['data']['order']['id'],
            $loyalty_account_id,
            $reward_tier_id,
            $order_id
          );

          if (!isset($redeemed['success']) || $redeemed['success'] === false) {
            return $this->handle_error($order_id, 'Unable to redeem reward, please contact us for help or remove the reward.');
          }

          // 6) If we have a valid Square order ID, fetch the updated order
          if (isset($square_order_response['data']['order']['id'])) {
            $square_order_response = $squareHelper->square_api_request(
              '/orders/' . $square_order_response['data']['order']['id']
            );
          }
        }
      }

      /*
       * --------------------------------------------------------------------
       *  RECONCILE  Woo (inc-tax)  ↔  Square net_amount_due (inc-tax)
       * ------------------------------------------------------------------
       */

      /* 0. Quick exit if we never got a valid $square_order_response */
      if (
        empty($square_order_response['success']) ||
        empty($square_order_response['data']['order']['id'])
      ) {
        // Charge the Woo total (less any gift-card) exactly as-is
        $total_amount = (int) round($total_amount - $gift_card_amount_cents);
      } else {  // ─────────────────────────── Square order does exist ───────────

        /* 1. Effective tax-factor for this order (e.g. 1.10 for 10 % GST) */
        $woo_tax_total = (float) $order->get_total_tax();
        $woo_total_inc = (float) $order->get_total();
        $tax_factor = ($woo_total_inc > 0 && $woo_tax_total > 0)
          ? 1 + ($woo_tax_total / ($woo_total_inc - $woo_tax_total))
          : 1.0;

        /* 2. Square's current net_amount_due (inclusive, in cents) */
        $sq_net = (int) $square_order_response['data']['order']['net_amount_due_money']['amount'];

        /* 3. Woo's amount we expect to collect (inclusive, in cents) */
        // Note: Subtract tip from WooCommerce total since tips are sent separately via tip_money
        $tip_amount_for_delta = $ordersController->extractTipAmount($order);
        $tip_amount_cents_for_delta = (int) round($tip_amount_for_delta * $multiplier);
        $woo_due_inc = (int) round($total_amount - $gift_card_amount_cents - $tip_amount_cents_for_delta);

        /* 4. Inclusive delta → applied 1-for-1 */
        $delta_inc = $woo_due_inc - $sq_net;  // +ve = Square short

        if ($delta_inc !== 0) {
          $patch = ($delta_inc > 0)
            ? ['service_charges' => [[
              'uid' => 'rounding-surcharge',
              'name' => 'Rounding Adjustment (+)',
              'scope' => 'ORDER',
              'calculation_phase' => 'TOTAL_PHASE',
              'amount_money' => [
                'amount' => $delta_inc,
                'currency' => $currency,
              ],
              'taxable' => false,
            ]]]
            : ['discounts' => [[
              'uid' => 'rounding-discount',
              'name' => 'Rounding Adjustment (-)',
              'amount_money' => [
                'amount' => abs($delta_inc),
                'currency' => $currency,
              ],
              'scope' => 'ORDER',
            ]]];

          /* Push the adjustment back to Square */
          $square_order_response = $squareHelper->square_api_request(
            '/orders/' . $square_order_response['data']['order']['id'],
            'PUT',
            [
              'idempotency_key' => wp_generate_uuid4(),
              'order' => $patch + [
                'location_id' => $locationId,
                'version' => $square_order_response['data']['order']['version'],
              ],
            ]
          );
        }

        /* 5. Fetch the authoritative total from Square */
        $sq_net = (int) ($square_order_response['data']['order']['net_amount_due_money']['amount'] ?? 0);
        $total_amount = max(0, $sq_net - $gift_card_amount_cents);
      }
      /* ───────────────────────────────────────────────────────────────────── */

      $settings = get_option('square-woo-sync_settings', []);

      // Extract tip amount from order fees for proper tip reporting
      $tip_amount = $ordersController->extractTipAmount($order);
      $tip_amount_cents = (int) round($tip_amount * $multiplier);

      // SCENARIOS:
      // If Gift Card is not set, fallback to your old single payment
      if (empty($gift_card_id)) {
        error_log("[SquareSync Gateway] Order #{$order_id}: Processing standard payment (no gift card)");

        // Prepare single payment data
        $payment_data = $this->prepare_payment_data(
          $square_token,
          $order_id,
          $total_amount,
          $currency,
          $square_customer_id,
          $locationId,
          $square_order_response,
          $tip_amount_cents
        );

        if (!empty($square_verification_token)) {
          $payment_data['verification_token'] = $square_verification_token;
          error_log("[SquareSync Gateway] Order #{$order_id}: Verification token included");
        }

        // Charge
        error_log("[SquareSync Gateway] Order #{$order_id}: Sending payment request to Square (Amount: {$total_amount} {$currency})");
        $payment_response = $squareHelper->square_api_request('/payments', 'POST', $payment_data, null, false);
        if (!$this->validate_payment_response($payment_response, $order_id)) {
          // if fail => restore loyalty, handle error
          $error_message = 'Square payment failed.';
          if (isset($payment_response['error'])) {
            $error_message = $payment_response['error'];
          }

          // Cancel the Square order if it was created to prevent orphaned orders
          if (isset($square_order_response['data']['order']['id'])) {
            $square_order_id = $square_order_response['data']['order']['id'];

            // Fetch the latest version of the order before cancelling
            // The version may have changed due to loyalty redemption or rounding adjustments
            $latest_order = $squareHelper->square_api_request("/orders/{$square_order_id}", 'GET');

            if (isset($latest_order['data']['order']['version'])) {
              $current_version = $latest_order['data']['order']['version'];

              // Cancel all fulfillments first (required by Square before order can be cancelled)
              if (isset($latest_order['data']['order']['fulfillments']) && is_array($latest_order['data']['order']['fulfillments'])) {
                $fulfillments_to_cancel = [];

                foreach ($latest_order['data']['order']['fulfillments'] as $fulfillment) {
                  if (isset($fulfillment['uid']) && isset($fulfillment['state']) && $fulfillment['state'] !== 'CANCELED') {
                    $fulfillments_to_cancel[] = [
                      'uid' => $fulfillment['uid'],
                      'state' => 'CANCELED'
                    ];
                  }
                }

                // Cancel all fulfillments in a single request
                if (!empty($fulfillments_to_cancel)) {
                  $fulfillment_cancel_result = $squareHelper->square_api_request(
                    "/orders/{$square_order_id}",
                    'PUT',
                    [
                      'idempotency_key' => wp_generate_uuid4(),
                      'order' => [
                        'version' => $current_version,
                        'location_id' => $locationId,
                        'fulfillments' => $fulfillments_to_cancel
                      ]
                    ]
                  );

                  // Update version after fulfillment cancellation
                  if (isset($fulfillment_cancel_result['data']['order']['version'])) {
                    $current_version = $fulfillment_cancel_result['data']['order']['version'];
                  }
                }
              }

              // Now cancel the order itself
              $cancel_result = $squareHelper->square_api_request(
                "/orders/{$square_order_id}",
                'PUT',
                [
                  'order' => [
                    'version' => $current_version,
                    'state' => 'CANCELED',
                    'location_id' => $locationId
                  ]
                ]
              );
            }
          }

          if ($redeeming_rewards && isset($square_order_response['data']['order'])) {
            $loyaltyRedeeming->restore_loyalty_points(
              $loyalty_account_id,
              $reward_tier_id,
              $order_id,
              $square_order_response['data']['order']
            );
          }
          return $this->handle_error($order_id, $error_message);
        }

        // success => finalize
        $payment_id = $payment_response['data']['payment']['id'];
        error_log("[SquareSync Gateway] Order #{$order_id}: Payment successful - Square Payment ID: {$payment_id}");

        // If split orders mode, store payment ID and queue background job
        if ($split_orders_enabled) {
          // Update the pending payment ID with actual payment ID
          $order->update_meta_data('_square_payment_id_pending', $payment_id);
          $order->save();

          // Queue the split order job
          require_once plugin_dir_path(__FILE__) . '../Jobs/SplitOrderJob.php';
          wp_queue()->push(
            new \Pixeldev\SquareWooSync\Jobs\SplitOrderJob($order_id),
            0 // Execute immediately
          );

          error_log("[SquareSync Gateway] Order #{$order_id}: Split order job queued with payment ID: {$payment_id}");
        }

        // Save new card if requested
        if (
          (isset($_POST['wc-' . $this->id . '-new-payment-method']) && 'true' === $_POST['wc-' . $this->id . '-new-payment-method']) ||
          (isset($_POST['wc-squaresync_credit-new-payment-method']) && '1' === $_POST['wc-squaresync_credit-new-payment-method'])
        ) {
          if (empty($token_id) || $token_id === 'new') {
            $card_response = $this->save_card_on_square($payment_id, $square_customer_id);
            if (!$card_response['success']) {
              wc_add_notice(__('There was a problem saving your payment method.', 'squarewoosync-pro'), 'error');
            } else {
              $card_data = $card_response['data']['card'];
              $payment_token = new \WC_Payment_Token_CC();
              $payment_token->set_token($card_data['id']);
              $payment_token->set_gateway_id($this->id);
              $payment_token->set_card_type(strtolower($card_data['card_brand']));
              $payment_token->set_last4($card_data['last_4']);
              $payment_token->set_expiry_month($card_data['exp_month']);
              $payment_token->set_expiry_year($card_data['exp_year']);
              $payment_token->set_user_id(get_current_user_id());
              $payment_token->save();
              // attach to order
              $order->add_payment_token($payment_token->get_id());
            }
          }
        }

        // finalize
        error_log("[SquareSync Gateway] Order #{$order_id}: Finalizing order payment");
        $this->finalize_order_payment($order, $payment_response, $square_order_response, $total_amount);
      } else {
        // GIFT CARD IS PRESENT
        // We must see if the gift card covers partial or full
        error_log("[SquareSync Gateway] Order #{$order_id}: Processing payment with gift card (ID: {$gift_card_id}, Amount: {$gift_card_amount_cents})");

        // Partial coverage scenario: Gift card covers part, we also have a card token?
        if (empty($square_token)) {
          // No card token, but not fully covered => error

          // Cancel the Square order if it was created to prevent orphaned orders
          if (isset($square_order_response['data']['order']['id'])) {
            $square_order_id = $square_order_response['data']['order']['id'];
            error_log("[SquareSync Gateway] Order #{$order_id}: Cancelling Square order {$square_order_id} due to insufficient payment method");
            $cancel_result = $squareHelper->square_api_request(
              "/orders/{$square_order_id}",
              'PUT',
              [
                'order' => [
                  'version' => $square_order_response['data']['order']['version'],
                  'state' => 'CANCELED',
                  'location_id' => $locationId
                ]
              ]
            );
            if (isset($cancel_result['success']) && $cancel_result['success']) {
              error_log("[SquareSync Gateway] Order #{$order_id}: Square order {$square_order_id} cancelled successfully");
            }
          }

          if ($redeeming_rewards && isset($square_order_response['data']['order'])) {
            $loyaltyRedeeming->restore_loyalty_points(
              $loyalty_account_id,
              $reward_tier_id,
              $order_id,
              $square_order_response['data']['order']
            );
          }
          return $this->handle_error($order_id, 'Gift Card does not fully cover the order, and no other payment method provided.');
        }

        $settings = get_option('square-woo-sync_settings', []);

        // 1) Payment #1 with Gift Card (autocomplete=false)
        $partial_giftcard_data = [
          'idempotency_key' => uniqid('gc-part-', true),
          'location_id' => $locationId,
          'source_id' => $gift_card_id,
          'order_id' => $square_order_response['data']['order']['id'] ?? '',
          'amount_money' => [
            'amount' => $gift_card_amount_cents,
            'currency' => $currency,
          ],
          'autocomplete' => false,
          'accept_partial_authorization' => true
        ];
        $gc_payment_resp = $squareHelper->square_api_request('/payments', 'POST', $partial_giftcard_data);

        if (!empty($gc_payment_resp['error'])) {
          // Cancel the Square order if it was created to prevent orphaned orders
          if (isset($square_order_response['data']['order']['id'])) {
            $square_order_id = $square_order_response['data']['order']['id'];
            error_log("[SquareSync Gateway] Order #{$order_id}: Cancelling Square order {$square_order_id} due to gift card payment failure");
            $cancel_result = $squareHelper->square_api_request(
              "/orders/{$square_order_id}",
              'PUT',
              [
                'order' => [
                  'version' => $square_order_response['data']['order']['version'],
                  'state' => 'CANCELED',
                  'location_id' => $locationId
                ]
              ]
            );
            if (isset($cancel_result['success']) && $cancel_result['success']) {
              error_log("[SquareSync Gateway] Order #{$order_id}: Square order {$square_order_id} cancelled successfully");
            }
          }

          if ($redeeming_rewards && isset($square_order_response['data']['order'])) {
            $loyaltyRedeeming->restore_loyalty_points(
              $loyalty_account_id,
              $reward_tier_id,
              $order_id,
              $square_order_response['data']['order']
            );
          }
          return $this->handle_error($order_id, 'Error authorizing gift card payment: ' . $gc_payment_resp['error']);
        }

        $giftcard_payment_id = $gc_payment_resp['data']['payment']['id'] ?? '';

        // 2) Payment #2 with Card for the remainder
        $payment_data = [
          'idempotency_key' => wp_generate_uuid4(),
          'source_id' => $square_token,
          'reference_id' => "Woo Order #$order_id",
          'autocomplete' => true,
          'amount_money' => ['amount' => $total_amount, 'currency' => $currency],
          'location_id' => $locationId,
          'autocomplete' => false,
          'order_id' => $square_order_response['data']['order']['id'] ?? '',
        ];

        // Only add customer ID if it's a valid string (not an array with error)
        if (!is_array($square_customer_id) && !empty($square_customer_id)) {
          $payment_data['customer_id'] = $square_customer_id;
        }

        if (!empty($square_verification_token)) {
          $payment_data['verification_token'] = $square_verification_token;
        }

        $card_pay_resp = $squareHelper->square_api_request('/payments', 'POST', $payment_data);

        if (!empty($card_pay_resp['error'])) {
          // Cancel the gift card payment if it succeeded
          if (!empty($giftcard_payment_id)) {
            $squareHelper->square_api_request("/payments/{$giftcard_payment_id}/cancel", 'POST');
          }

          // Cancel the Square order if it was created to prevent orphaned orders
          if (isset($square_order_response['data']['order']['id'])) {
            $square_order_id = $square_order_response['data']['order']['id'];
            error_log("[SquareSync Gateway] Order #{$order_id}: Cancelling Square order {$square_order_id} due to card payment failure");
            $cancel_result = $squareHelper->square_api_request(
              "/orders/{$square_order_id}",
              'PUT',
              [
                'order' => [
                  'version' => $square_order_response['data']['order']['version'],
                  'state' => 'CANCELED',
                  'location_id' => $locationId
                ]
              ]
            );
            if (isset($cancel_result['success']) && $cancel_result['success']) {
              error_log("[SquareSync Gateway] Order #{$order_id}: Square order {$square_order_id} cancelled successfully");
            }
          }

          // restore loyalty
          if ($redeeming_rewards && isset($square_order_response['data']['order'])) {
            $loyaltyRedeeming->restore_loyalty_points(
              $loyalty_account_id,
              $reward_tier_id,
              $order_id,
              $square_order_response['data']['order']
            );
          }
          return $this->handle_error($order_id, 'Error authorizing card payment: ' . $card_pay_resp['error']);
        }
        $card_payment_id = $card_pay_resp['data']['payment']['id'] ?? '';

        // 3) Now "pay order" with the two authorized payments
        if (!empty($giftcard_payment_id) || !empty($card_payment_id)) {
          $payment_ids = [];
          if ($giftcard_payment_id)
            $payment_ids[] = $giftcard_payment_id;
          if ($card_payment_id)
            $payment_ids[] = $card_payment_id;

          $new_square_order = $squareHelper->square_api_request(
            '/orders/' . $square_order_response['data']['order']['id']
          );
          $square_order = $new_square_order['data']['order'] ?? [];

          // Pay order
          $payOrderData = [
            'idempotency_key' => uniqid('pay-', true),
            'order_version' => $square_order['version'],
            'payment_ids' => $payment_ids,
          ];
          $pay_resp = $squareHelper->square_api_request(
            '/orders/' . $square_order_response['data']['order']['id'] . '/pay',
            'POST',
            $payOrderData
          );
          if (!empty($pay_resp['error'])) {
            // Cancel both payments
            $squareHelper->square_api_request("/payments/{$giftcard_payment_id}/cancel", 'POST');
            $squareHelper->square_api_request("/payments/{$card_payment_id}/cancel", 'POST');

            // Cancel the Square order if it was created to prevent orphaned orders
            if (isset($square_order_response['data']['order']['id'])) {
              $square_order_id = $square_order_response['data']['order']['id'];
              error_log("[SquareSync Gateway] Order #{$order_id}: Cancelling Square order {$square_order_id} due to pay order failure");
              $cancel_result = $squareHelper->square_api_request(
                "/orders/{$square_order_id}",
                'PUT',
                [
                  'order' => [
                    'version' => $square_order['version'],
                    'state' => 'CANCELED',
                    'location_id' => $locationId
                  ]
                ]
              );
              if (isset($cancel_result['success']) && $cancel_result['success']) {
                error_log("[SquareSync Gateway] Order #{$order_id}: Square order {$square_order_id} cancelled successfully");
              }
            }

            if ($redeeming_rewards && isset($square_order_response['data']['order'])) {
              $loyaltyRedeeming->restore_loyalty_points(
                $loyalty_account_id,
                $reward_tier_id,
                $order_id,
                $square_order_response['data']['order']
              );
            }
            return $this->handle_error($order_id, 'Error paying order with multiple payments: ' . $pay_resp['error']);
          }
        }

        // (Optional) If user wants to save the new card
        if (
          (isset($_POST['wc-' . $this->id . '-new-payment-method']) && 'true' === $_POST['wc-' . $this->id . '-new-payment-method']) ||
          (isset($_POST['wc-squaresync_credit-new-payment-method']) && '1' === $_POST['wc-squaresync_credit-new-payment-method'])
        ) {
          if (empty($token_id) || $token_id === 'new') {
            // We can use the card_payment_id to save the card
            // But only if a card payment was actually made
            if (!empty($card_payment_id)) {
              $card_response = $this->save_card_on_square($card_payment_id, $square_customer_id);
              if (!$card_response['success']) {
                wc_add_notice(__('Problem saving your card with partial coverage.', 'squarewoosync-pro'), 'error');
              } else {
                $card_data = $card_response['data']['card'];
                $new_token = new \WC_Payment_Token_CC();
                $new_token->set_token($card_data['id']);
                $new_token->set_gateway_id($this->id);
                $new_token->set_card_type(strtolower($card_data['card_brand']));
                $new_token->set_last4($card_data['last_4']);
                $new_token->set_expiry_month($card_data['exp_month']);
                $new_token->set_expiry_year($card_data['exp_year']);
                $new_token->set_user_id(get_current_user_id());
                $new_token->save();
                $order->add_payment_token($new_token->get_id());
              }
            }
          }
        }

        $square_data = ['order' => $square_order_response, 'payment' => $pay_resp];
        $order->update_meta_data('square_data', wp_json_encode($square_data));
        if (isset($square_order_response['data']['order']['id'])) {
          $order->update_meta_data('square_order_id', $square_order_response['data']['order']['id']);

          do_action(
            'squarewoosync_square_order_created',
            $square_order_response['data']['order']['id'],
            $order->get_id()
          );
        }

        // Mark order paid in Woo
        $order->payment_complete();
        $order->add_order_note(__('Gift Card + Card partial coverage in Square.', 'squarewoosync-pro'));
      }

      // Handle subscriptions (attach token if available)
      if (class_exists('WC_Subscriptions') && wcs_order_contains_subscription($order)) {
        if ($payment_token && $payment_token->get_id()) {
          $subscriptions = wcs_get_subscriptions_for_order($order);

          foreach ($subscriptions as $subscription) {
            $subscription->update_meta_data('_payment_method_token', $payment_token->get_id());
            $subscription->set_payment_method($this->id);

            if (method_exists($subscription, 'add_payment_token')) {
              $subscription->add_payment_token($payment_token->get_id());
            }

            $subscription->save();
          }
        }
      }

      // Clear the cart
      WC()->cart->empty_cart();

      // If loyalty is enabled and we are NOT redeeming rewards, schedule point accumulation
      if (
        $loyalty_enabled &&
        !$redeeming_rewards &&
        isset($square_order_response['data']['order']['id']) &&
        isset($square_customer_id) &&
        class_exists('Pixeldev\\SquareWooSync\\Loyalty\\LoyaltyProgram')
      ) {
        $loyaltyProgram = new LoyaltyProgram();
        $loyaltyProgram->schedule_loyalty_points_accumulation($order_id);
      }
      if (WC()->session && is_object(WC()->session)) {
        // Clear session loyalty data
        WC()->session->__unset('applied_reward_name');
        WC()->session->__unset('applied_reward_points');
        WC()->session->__unset('loyalty_account_id');
        WC()->session->__unset('reward_tier_id');
        WC()->session->__unset('store_credit_discount_type');
        WC()->session->__unset('store_credit_discount_amount');
        WC()->session->__unset('applied_gift_card_code');
        WC()->session->__unset('applied_gift_card_amount');
        WC()->session->__unset('applied_gift_card_id');
        WC()->session->__unset('applied_gift_card_balance');
      }

      error_log("[SquareSync Gateway] Order #{$order_id}: Payment processing completed successfully");
      return ['result' => 'success', 'redirect' => $this->get_return_url($order)];
    } catch (\Exception $e) {
      error_log("[SquareSync Gateway] Order #{$order_id}: Exception occurred during payment processing - " . $e->getMessage());
      error_log("[SquareSync Gateway] Order #{$order_id}: Stack trace: " . $e->getTraceAsString());
      return $this->handle_exception($order_id, $e);
    }
  }

  private function check_net_amount_due($square_order_response, $total_amount, $currency, $order_id)
  {
    $net_amount_due = $square_order_response['data']['order']['net_amount_due_money']['amount'] ?? 0;
    $net_currency = $square_order_response['data']['order']['net_amount_due_money']['currency'] ?? '';

    if ($net_amount_due != $total_amount || $net_currency != $currency) {
      error_log("Warning: Net amount due ($net_amount_due $net_currency) does not match the expected amount ($total_amount $currency) for Order ID: $order_id.");
    }
  }

  // Error handling function
  private function handle_error($order_id, $message)
  {
    // Recalculate the cart totals
    WC()->cart->calculate_totals();
    wc_add_notice(__('Payment error: ', 'squarewoosync-pro') . $message, 'error');
    return ['result' => 'failure', 'redirect' => wc_get_checkout_url()];
  }

  // Attempt to create Square order, return false if unsuccessful but do not halt process
  private function attempt_create_square_order($ordersController, $order, $square_customer_id, $squareHelper, $order_id, $location_id)
  {
    error_log("[SquareSync Gateway] Order #{$order_id}: Attempting to create Square order");
    error_log("[SquareSync Gateway] Order #{$order_id}: Location ID: {$location_id}");

    if (is_array($square_customer_id) || empty($square_customer_id)) {
      error_log("[SquareSync Gateway] Order #{$order_id}: Invalid Square customer ID - cannot create order");
      $order->add_order_note(__('Square order creation failed: Invalid Square customer ID.', 'squarewoosync-pro'));
      return false;
    }

    error_log("[SquareSync Gateway] Order #{$order_id}: Preparing Square order data");
    $order_data = $ordersController->prepareSquareOrderData($order, $square_customer_id, $location_id);

    error_log("[SquareSync Gateway] Order #{$order_id}: Sending create order request to Square API");
    $square_order_response = $ordersController->createOrderInSquare($order_data, $squareHelper);

    if (!isset($square_order_response['success']) || $square_order_response['success'] === false) {
      $error_msg = json_encode($square_order_response['error'] ?? 'Unknown error');
      error_log("[SquareSync Gateway] Order #{$order_id}: Square order creation FAILED - {$error_msg}");
      error_log("[SquareSync Gateway] Order #{$order_id}: Full Square API response: " . json_encode($square_order_response));

      // Add order note for visibility in WooCommerce admin
      $error_detail = is_array($square_order_response['error'])
        ? wp_json_encode($square_order_response['error'])
        : ($square_order_response['error'] ?? 'Unknown error');
      $order->add_order_note(
        sprintf(
          __('Square order creation failed: %s', 'squarewoosync-pro'),
          $error_detail
        )
      );

      return false;
    }

    $square_order_id = $square_order_response['data']['order']['id'] ?? 'N/A';
    error_log("[SquareSync Gateway] Order #{$order_id}: Square order created successfully - Square Order ID: {$square_order_id}");
    return $square_order_response;
  }

  // Prepare payment data
  private function prepare_payment_data($token, $order_id, $total_amount, $currency, $square_customer_id, $location_id, $square_order_response, $tip_amount_cents = 0)
  {
    // Note: $total_amount passed here is already the Square order's net_amount_due (without tip)
    // because it's calculated from the Square order response after delta adjustments.
    // We do NOT subtract the tip again here - just use $total_amount as-is for the payment.
    $payment_amount = $total_amount;

    $payment_data = [
      'idempotency_key' => wp_generate_uuid4(),
      'source_id' => $token,
      'reference_id' => "Woo Order #$order_id",
      'autocomplete' => true,
      'amount_money' => ['amount' => $payment_amount, 'currency' => $currency],
      'location_id' => $location_id,
    ];

    // Add tip_money if there's a tip amount
    if ($tip_amount_cents > 0) {
      $payment_data['tip_money'] = [
        'amount' => $tip_amount_cents,
        'currency' => $currency,
      ];
      error_log("[SquareSync Gateway] Order #{$order_id}: Adding tip_money to payment - Amount: {$tip_amount_cents} {$currency}");
    }

    // Only add customer ID if it's a valid string (not an array with error)
    if (!is_array($square_customer_id) && !empty($square_customer_id)) {
      $payment_data['customer_id'] = $square_customer_id;
    }

    // Add order ID if the order was created successfully
    // When tips are involved, we always attach the order_id because the payment amount
    // (without tip) + tip_money will equal the correct total
    if (isset($square_order_response['data']['order']['id'])) {
      $payment_data['order_id'] = $square_order_response['data']['order']['id'];

      $square_order_net_amount_due = $square_order_response['data']['order']['net_amount_due_money']['amount'] ?? 'N/A';
      error_log("[SquareSync Gateway] Order #{$order_id}: Order ID attached to payment. Square net due: {$square_order_net_amount_due}, Payment: {$payment_amount}, Tip: {$tip_amount_cents}");
    }

    return $payment_data;
  }

  // Validate payment response
  private function validate_payment_response($payment_response, $order_id)
  {
    if (!isset($payment_response['success']) || $payment_response['success'] === false) {
      $error_detail = json_encode($payment_response['error'] ?? 'Unknown error');
      error_log("[SquareSync Gateway] Order #{$order_id}: Payment validation FAILED - {$error_detail}");
      return false;
    }
    error_log("[SquareSync Gateway] Order #{$order_id}: Payment validation successful");
    return true;
  }

  // Finalize the order payment
  private function finalize_order_payment($order, $payment_response, $square_order_response, $total_amount)
  {
    $order_id = $order->get_id();
    error_log("[SquareSync Gateway] Order #{$order_id}: Finalizing order payment");

    $ordersController = new OrdersController();
    $multiplier = $ordersController->get_currency_multiplier($order->get_currency());

    // Check if in split order mode
    $is_split_mode = $order->get_meta('_square_order_pending_split');

    if ($is_split_mode) {
      error_log("[SquareSync Gateway] Order #{$order_id}: Split mode detected - deferring Square order data save to background job");
    }

    // Only save square order data if not in split mode (split mode will handle this in background)
    if (!$is_split_mode) {
      $square_data = ['order' => $square_order_response, 'payment' => $payment_response];
      $order->update_meta_data('square_data', wp_json_encode($square_data));
      if (isset($square_order_response['data']['order']['id'])) {
        $square_order_id = $square_order_response['data']['order']['id'];
        $order->update_meta_data('square_order_id', $square_order_id);
        error_log("[SquareSync Gateway] Order #{$order_id}: Saved Square order ID: {$square_order_id}");

        do_action(
          'squarewoosync_square_order_created',
          $square_order_id,
          $order_id
        );
        error_log("[SquareSync Gateway] Order #{$order_id}: Fired squarewoosync_square_order_created action");
      }
    }

    $payment_id = $payment_response['data']['payment']['id'];
    error_log("[SquareSync Gateway] Order #{$order_id}: Marking order as payment complete with Square Payment ID: {$payment_id}");
    $order->payment_complete($payment_id);

    $order->add_order_note(sprintf(
      // translators: 1: formatted payment amount; 2: Square transaction ID.
      __('Payment of %1$s via Square successfully completed (Square Transaction ID: %2$s)', 'squarewoosync-pro'),
      wc_price($total_amount / $multiplier),
      $payment_response['data']['payment']['id']
    ));

  }

  // Handle exceptions
  private function handle_exception($order_id, $exception)
  {
    if (WC()->session && is_object(WC()->session)) {
      // Clear session loyalty data
      WC()->session->__unset('applied_reward_name');
      WC()->session->__unset('applied_reward_points');
      WC()->session->__unset('loyalty_account_id');
      WC()->session->__unset('reward_tier_id');
      WC()->session->__unset('store_credit_discount_type');
      WC()->session->__unset('store_credit_discount_amount');
      WC()->session->__unset('applied_gift_card_code');
      WC()->session->__unset('applied_gift_card_amount');
      WC()->session->__unset('applied_gift_card_id');
      WC()->session->__unset('applied_gift_card_balance');
    }

    wc_add_notice(__('Payment error: An unexpected error occurred. Please try again.', 'squarewoosync-pro'), 'error');
    error_log("Payment processing exception for Order ID: $order_id - " . $exception->getMessage());
    return ['result' => 'failure', 'redirect' => wc_get_checkout_url()];
  }

  /**
   * Handle adding a payment method from 'My Account' page.
   */
  public function add_payment_method()
  {
    // Verify nonce for security
    if (!isset($_POST['nonce_sec']) || !wp_verify_nonce($_POST['nonce_sec'], 'sws_add_payment_method')) {
      wc_add_notice(__('Nonce verification failed', 'squarewoosync-pro'), 'error');
      wp_redirect(wc_get_account_endpoint_url('payment-methods'));
      exit;
    }

    $token = sanitize_text_field($_POST['square_payment_token'] ?? '');

    if (empty($token)) {
      wc_add_notice(__('Payment token is missing.', 'squarewoosync-pro'), 'error');
      wp_redirect(wc_get_account_endpoint_url('payment-methods'));
      exit;
    }

    $user_id = get_current_user_id();
    $squareHelper = new SquareHelper();

    // Use the new method to get or create the Square customer ID
    $square_customer_id = $this->getOrCreateSquareCustomerByUser($user_id, $squareHelper);

    if (!$square_customer_id) {
      wc_add_notice(__('Could not retrieve or create Square customer.', 'squarewoosync-pro'), 'error');
      wp_redirect(wc_get_account_endpoint_url('payment-methods'));
      exit;
    }

    // Save the card on Square and get card details
    $card_response = $this->save_card_on_square($token, $square_customer_id);

    if (!$card_response['success']) {
      wc_add_notice(__('There was a problem adding your payment method: Invalid card data.', 'squarewoosync-pro'), 'error');
      wp_redirect(wc_get_account_endpoint_url('payment-methods'));
      exit;
    }

    $card_data = $card_response['data']['card'];

    // Create a new payment token
    $payment_token = new \WC_Payment_Token_CC();
    $payment_token->set_token($card_data['id']);  // The card ID from Square
    $payment_token->set_gateway_id($this->id);
    $payment_token->set_card_type(strtolower($card_data['card_brand']));
    $payment_token->set_last4($card_data['last_4']);
    $payment_token->set_expiry_month($card_data['exp_month']);
    $payment_token->set_expiry_year($card_data['exp_year']);
    $payment_token->set_user_id($user_id);
    $payment_token->save();

    if ($payment_token->get_id()) {
      // Success
      wc_add_notice(__('Payment method added successfully.', 'squarewoosync-pro'), 'success');
    } else {
      wc_add_notice(__('There was a problem saving your payment method.', 'squarewoosync-pro'), 'error');
    }

    // Redirect to the payment methods page
    wp_redirect(wc_get_account_endpoint_url('payment-methods'));
    exit;
  }

  /**
   * Save a card on Square for a customer and retrieve card details.
   *
   * @param string $token               The payment token (nonce) received from Square's payment form.
   * @param string $square_customer_id  The Square customer ID to associate the card with.
   * @return array                      An array containing 'success' and either 'data' or 'errors'.
   */
  public function save_card_on_square($payment_id, $square_customer_id)
  {
    // Generate a unique idempotency key
    $idempotency_key = uniqid('sq-', true);

    // Build the request payload according to Square's API
    $body = [
      'idempotency_key' => $idempotency_key,
      'source_id' => $payment_id,  // Use the payment ID as the source_id
      'card' => [
        'customer_id' => $square_customer_id,
      ],
    ];

    $squareHelper = new SquareHelper();
    // Make the API request to Square's /cards endpoint
    $response = $squareHelper->square_api_request('/cards', 'POST', $body);

    // Check for errors in the response
    if (isset($response['error'])) {
      // Handle errors
      return [
        'success' => false,
        'errors' => $response['error'],
      ];
    } else {
      // Success
      return [
        'success' => true,
        'data' => $response['data'],
      ];
    }
  }

  /**
   * Get or create Square customer without relying on order data.
   */
  public function getOrCreateSquareCustomerByUser($user_id, $squareHelper)
  {
    // Check if the user has the 'square_customer_id' meta field
    $square_customer_id = get_user_meta($user_id, 'square_customer_id', true);

    if (!empty($square_customer_id)) {
      // Return the Square customer ID from user meta
      return $square_customer_id;
    }

    // Get the user's email and name
    $user_info = get_userdata($user_id);
    $user_email = $user_info->user_email;

    // Proceed to search for the customer via Square API using the user's email
    $search_customer_result = $squareHelper->square_api_request('/customers/search', 'POST', [
      'query' => ['filter' => ['email_address' => ['exact' => $user_email]]]
    ]);

    // If customer already exists in Square, return the ID and update user meta
    if (!empty($search_customer_result['data']['customers'])) {
      $square_customer_id = $search_customer_result['data']['customers'][0]['id'];

      // Save the Square customer ID to user meta for future use
      update_user_meta($user_id, 'square_customer_id', $square_customer_id);

      return $square_customer_id;
    }

    // Customer doesn't exist in Square, attempt to create a new one
    $new_customer_data = [
      'given_name' => $user_info->first_name,
      'family_name' => $user_info->last_name,
      'email_address' => $user_email,
      // Add other fields as needed
    ];

    $create_customer_result = $squareHelper->square_api_request('/customers', 'POST', $new_customer_data);

    if (!empty($create_customer_result['data']['customer']['id'])) {
      $square_customer_id = $create_customer_result['data']['customer']['id'];

      // Save the new Square customer ID to user meta
      update_user_meta($user_id, 'square_customer_id', $square_customer_id);

      // Return the new customer ID
      return $square_customer_id;
    }

    // Handle cases where customer creation failed
    return false;
  }

  /**
   * Process a refund through Square API
   *
   * @param int $order_id Order ID
   * @param float $amount Refund amount
   * @param string $reason Refund reason
   * @return bool|WP_Error True on success, WP_Error on failure
   */
  public function process_refund($order_id, $amount = null, $reason = '')
  {
    // Validate refund amount
    if (!$amount || $amount <= 0) {
      return new WP_Error('invalid_amount', __('Refund amount must be greater than zero.', 'squarewoosync-pro'));
    }

    $order = wc_get_order($order_id);
    if (!$order) {
      return new WP_Error('invalid_order', __('Invalid order ID.', 'squarewoosync-pro'));
    }

    // Only process refunds for orders paid with this gateway
    if ($order->get_payment_method() !== $this->id) {
      return new WP_Error('invalid_gateway', __('This order was not paid with Square.', 'squarewoosync-pro'));
    }

    // Get Square payment data from order meta
    $square_data = $order->get_meta('square_data');
    if (!$square_data) {
      return new WP_Error('no_square_data', __('Square payment data not found for this order.', 'squarewoosync-pro'));
    }

    $square_data = json_decode($square_data, true);

    // Extract payment information
    $payment_data = $square_data['payment']['data']['payment'] ?? null;
    if (!$payment_data) {
      return new WP_Error('invalid_payment_data', __('Invalid Square payment data structure.', 'squarewoosync-pro'));
    }

    $payment_id = $payment_data['id'] ?? null;
    $payment_status = $payment_data['status'] ?? null;
    $original_amount = $payment_data['amount_money']['amount'] ?? 0;
    $currency = $payment_data['amount_money']['currency'] ?? $order->get_currency();
    $payment_version_token = $payment_data['version_token'] ?? null;

    if (!$payment_id) {
      return new WP_Error('missing_payment_id', __('Square payment ID not found.', 'squarewoosync-pro'));
    }

    // Get the latest payment data from Square to ensure we have the current version token
    $squareHelper = new SquareHelper();
    $payment_response = $squareHelper->square_api_request('/payments/' . $payment_id, 'GET');

    if (isset($payment_response['data']['payment'])) {
      // Update our payment data with the latest from Square
      $payment_data = $payment_response['data']['payment'];
      $payment_version_token = $payment_data['version_token'] ?? null;

      // Update the stored square_data with the latest payment data
      $square_data['payment']['data']['payment'] = $payment_data;
      $order->update_meta_data('square_data', json_encode($square_data));
      $order->save();
    }

    // Validate payment status - can only refund COMPLETED payments
    if ($payment_status !== 'COMPLETED') {
      return new WP_Error(
        'invalid_payment_status',
        sprintf(__('Cannot refund payment with status: %s. Only COMPLETED payments can be refunded.', 'squarewoosync-pro'), $payment_status)
      );
    }

    // Check payment date (Square only allows refunds within 1 year)
    $payment_date = $payment_data['created_at'] ?? null;
    if ($payment_date) {
      $payment_timestamp = strtotime($payment_date);
      $one_year_ago = strtotime('-1 year');
      if ($payment_timestamp < $one_year_ago) {
        return new WP_Error('payment_too_old', __('Cannot refund payments older than 1 year.', 'squarewoosync-pro'));
      }
    }

    // Validate refund amount doesn't exceed original payment
    $decimals           = wc_get_price_decimals();           // 0 for JPY, 2 for AUD, 3 for KWD …
    $factor             = (int) pow(10, $decimals);          // 1, 100, 1000 …
    $refund_amount_unit = (int) round($amount * $factor);    // integer for Square
    $original_amount_units = (int) round($original_amount * $factor);    // integer for Square

    if ($refund_amount_unit > $original_amount_units) {
      return new WP_Error('refund_too_large', __('Refund amount cannot exceed the original payment amount.', 'squarewoosync-pro'));
    }

    // Initialize Square Helper
    $squareHelper = new SquareHelper();

    // Prepare refund data
    $refund_data = [
      'idempotency_key' => wp_generate_uuid4(),
      'payment_id' => $payment_id,
      'amount_money' => [
        'amount' => $refund_amount_unit,
        'currency' => $currency
      ]
    ];

    // Add reason if provided
    if (!empty($reason)) {
      $refund_data['reason'] = $reason;
    }

    // Add payment version token for optimistic concurrency if available
    if ($payment_version_token) {
      $refund_data['payment_version_token'] = $payment_version_token;
    }

    // Make refund API request
    $response = $squareHelper->square_api_request('/refunds', 'POST', $refund_data);

    if (isset($response['error'])) {
      $error_message = is_array($response['error'])
        ? (isset($response['error']['detail']) ? $response['error']['detail'] : json_encode($response['error']))
        : $response['error'];

      return new WP_Error(
        'refund_api_error',
        sprintf(__('Square refund failed: %s', 'squarewoosync-pro'), $error_message)
      );
    }

    $refund_response = $response['data']['refund'] ?? null;
    if (!$refund_response) {
      return new WP_Error('invalid_refund_response', __('Invalid refund response from Square.', 'squarewoosync-pro'));
    }

    $refund_status = $refund_response['status'] ?? null;
    $refund_id = $refund_response['id'] ?? null;

    // Check if refund was successful
    if (in_array($refund_status, ['PENDING', 'COMPLETED'])) {
      // Store refund information in order meta
      $existing_refunds = get_post_meta($order_id, 'square_refunds', true);
      if (!is_array($existing_refunds)) {
        $existing_refunds = [];
      }

      $existing_refunds[] = [
        'refund_id' => $refund_id,
        'amount' => $amount,
        'currency' => $currency,
        'status' => $refund_status,
        'reason' => $reason,
        'created_at' => current_time('mysql'),
        'square_response' => $refund_response
      ];

      update_post_meta($order_id, 'square_refunds', $existing_refunds);

      // Add order note
      $order->add_order_note(
        sprintf(
          __('Square refund processed successfully. Amount: %1$s, Status: %2$s, Refund ID: %3$s%4$s', 'squarewoosync-pro'),
          wc_price($amount),
          $refund_status,
          $refund_id,
          !empty($reason) ? ', Reason: ' . $reason : ''
        )
      );

      // Handle inventory restocking if enabled
      $this->handle_refund_inventory_restock($order, $amount, $refund_id);

      return true;
    } else {
      return new WP_Error(
        'refund_failed',
        sprintf(__('Square refund failed with status: %s', 'squarewoosync-pro'), $refund_status)
      );
    }
  }

  /**
   * Handle inventory restocking after a successful refund
   *
   * @param WC_Order $order The WooCommerce order
   * @param float $refund_amount The refund amount
   * @param string $refund_id Square refund ID
   * @return void
   */
  private function handle_refund_inventory_restock($order, $refund_amount, $refund_id)
  {
    try {
      // Check if restock was requested in the refund
      $restock_refunded_items = isset($_REQUEST['restock_refunded_items']) &&
        $_REQUEST['restock_refunded_items'] === 'true';

      if (!$restock_refunded_items) {
        // Add debug log
        $order->add_order_note(
          __('Square inventory restock skipped: "Restock refunded items" was not selected.', 'squarewoosync-pro')
        );
        return;
      }

      // Get line items - prioritize refund data if available, otherwise use order data
      $refunded_line_items = [];
      // First, try to get refund data line items
      $refunds = $order->get_refunds();
      $latest_refund = !empty($refunds) ? current($refunds) : null;

      if ($latest_refund && !empty($latest_refund->get_items())) {
        foreach ($latest_refund->get_items() as $item) {
          $quantity = abs($item->get_quantity());  // Get absolute value since refund quantities are negative
          if ($quantity <= 0)
            continue;

          $refunded_line_items[] = [
            'product_id' => $item->get_product_id(),
            'variation_id' => $item->get_variation_id(),
            'quantity' => $quantity
          ];
        }
      } else {
        // Fallback to order data if no refund line items exist
        $order_items = $order->get_items();

        foreach ($order_items as $item) {
          $quantity = $item->get_quantity();
          if ($quantity <= 0)
            continue;

          $refunded_line_items[] = [
            'product_id' => $item->get_product_id(),
            'variation_id' => $item->get_variation_id(),
            'quantity' => $quantity
          ];
        }
      }

      // Add order note with restock details
      if (!empty($refunded_line_items)) {
        $order->add_order_note(
          sprintf(
            __('Square restock: Preparing to restock %d items', 'squarewoosync-pro'),
            count($refunded_line_items)
          )
        );
      }

      if (empty($refunded_line_items)) {
        return;  // No items to restock
      }

      // Prepare inventory data for Square
      $inventory_data = $this->prepare_inventory_restock_data($refunded_line_items);

      if (empty($inventory_data)) {
        $order->add_order_note(__('Square inventory restock skipped: No valid Square catalog items found.', 'squarewoosync-pro'));
        return;
      }

      // Initialize Square Helper and update inventory
      $squareHelper = new SquareHelper();
      $inventory_result = $squareHelper->update_inventory($inventory_data);

      if ($inventory_result['success']) {
        $order->add_order_note(
          sprintf(
            __('Square inventory restocked successfully for refund %1$s. Updated %2$d items.', 'squarewoosync-pro'),
            $refund_id,
            count($inventory_data)
          )
        );

        // Store inventory restock information in order meta
        $existing_restocks = get_post_meta($order->get_id(), 'square_inventory_restocks', true);
        if (!is_array($existing_restocks)) {
          $existing_restocks = [];
        }

        $existing_restocks[] = [
          'refund_id' => $refund_id,
          'items_restocked' => count($inventory_data),
          'created_at' => current_time('mysql'),
          'inventory_data' => $inventory_data
        ];

        update_post_meta($order->get_id(), 'square_inventory_restocks', $existing_restocks);
      } else {
        $error_message = isset($inventory_result['error']) ? $inventory_result['error'] : 'Unknown error';
        $order->add_order_note(
          sprintf(
            __('Square inventory restock failed for refund %1$s: %2$s', 'squarewoosync-pro'),
            $refund_id,
            $error_message
          )
        );
      }
    } catch (Exception $e) {
      $order->add_order_note(
        sprintf(
          __('Square inventory restock error for refund %1$s: %2$s', 'squarewoosync-pro'),
          $refund_id,
          $e->getMessage()
        )
      );
    }
  }

  /**
   * Prepare inventory data for Square restocking
   *
   * @param array $refunded_items Array of refunded items with product_id, variation_id, quantity
   * @return array Formatted inventory data for Square API
   */
  private function prepare_inventory_restock_data($refunded_items)
  {
    $inventory_data = [];
    $settings = get_option('square-woo-sync_settings', []);
    $location_id = $settings['location'] ?? '';

    if (empty($location_id)) {
      return $inventory_data;  // No location configured
    }

    foreach ($refunded_items as $item) {
      $product_id = $item['variation_id'] > 0 ? $item['variation_id'] : $item['product_id'];
      $product = wc_get_product($product_id);

      if (!$product) {
        continue;
      }

      // Get Square catalog object ID from product meta
      // For simple products (variation_id = 0), use square_variation_id
      // For variations (variation_id > 0), use square_product_id
      if ($item['variation_id'] > 0) {
        $catalog_object_id = get_post_meta($product_id, 'square_product_id', true);
      } else {
        $catalog_object_id = get_post_meta($product_id, 'square_variation_id', true);
      }

      if (empty($catalog_object_id)) {
        continue;  // No Square catalog ID found
      }

      // Get current WooCommerce stock level
      $current_stock = $product->get_stock_quantity();
      if ($current_stock === null || $current_stock === '') {
        $current_stock = 0;  // Default to 0 if stock management is disabled
      }

      // Calculate total stock after restocking (current + refunded quantity)
      $total_stock_after_restock = $current_stock + $item['quantity'];

      // Format inventory data according to SquareHelper::update_inventory expectations
      // Square requires the TOTAL stock quantity, not the delta
      $inventory_data[] = [
        'catalog_object_id' => $catalog_object_id,
        'location_id' => $location_id,
        'quantity' => $total_stock_after_restock,  // Total stock quantity after restock
        'state' => 'IN_STOCK'
      ];
    }

    return $inventory_data;
  }
}
