<?php
/**
 * Payment Gateway REST API
 *
 * Handles REST API endpoints for payment gateways including webhooks.
 *
 * @package GGM_Commerce
 */

// If this file is called directly, abort.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
// phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
// phpcs:disable PluginCheck.Security.DirectDB.UnescapedDBParameter

/**
 * Class GGM_Commerce_Gateway_REST_API
 *
 * Registers and handles REST API endpoints for payment processing.
 */
class GGM_Commerce_Gateway_REST_API {

	/**
	 * Namespace for REST routes.
	 *
	 * @var string
	 */
	const NAMESPACE = 'ggm-commerce/v1';

	/**
	 * Single instance of the class.
	 *
	 * @var GGM_Commerce_Gateway_REST_API|null
	 */
	private static $instance = null;

	/**
	 * Get single instance of the class.
	 *
	 * @return GGM_Commerce_Gateway_REST_API
	 */
	public static function instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Constructor.
	 */
	private function __construct() {
		add_action( 'rest_api_init', array( $this, 'register_routes' ) );
	}

	/**
	 * Register REST API routes.
	 *
	 * @return void
	 */
	public function register_routes() {
		// Stripe webhook endpoint.
		register_rest_route(
			self::NAMESPACE,
			'/webhooks/stripe',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'handle_stripe_webhook' ),
				'permission_callback' => '__return_true',
			)
		);

		// PayPal webhook endpoint.
		register_rest_route(
			self::NAMESPACE,
			'/webhooks/paypal',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'handle_paypal_webhook' ),
				'permission_callback' => '__return_true',
			)
		);

		// Create Stripe PaymentIntent.
		register_rest_route(
			self::NAMESPACE,
			'/stripe/create-intent',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'create_stripe_intent' ),
				'permission_callback' => array( $this, 'verify_payment_nonce' ),
				'args'                => array(
					'order_id' => array(
						'required'          => true,
						'type'              => 'integer',
						'sanitize_callback' => 'absint',
					),
				),
			)
		);

		// Confirm Stripe payment.
		register_rest_route(
			self::NAMESPACE,
			'/stripe/confirm-payment',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'confirm_stripe_payment' ),
				'permission_callback' => array( $this, 'verify_payment_nonce' ),
				'args'                => array(
					'payment_intent_id' => array(
						'required'          => true,
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
					),
				),
			)
		);

		// Create PayPal order.
		register_rest_route(
			self::NAMESPACE,
			'/paypal/create-order',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'create_paypal_order' ),
				'permission_callback' => array( $this, 'verify_payment_nonce' ),
				'args'                => array(
					'order_id' => array(
						'required'          => true,
						'type'              => 'integer',
						'sanitize_callback' => 'absint',
					),
				),
			)
		);

		// Capture PayPal order.
		register_rest_route(
			self::NAMESPACE,
			'/paypal/capture-order',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'capture_paypal_order' ),
				'permission_callback' => array( $this, 'verify_payment_nonce' ),
				'args'                => array(
					'paypal_order_id' => array(
						'required'          => true,
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
					),
					'order_id'        => array(
						'required'          => true,
						'type'              => 'integer',
						'sanitize_callback' => 'absint',
					),
				),
			)
		);

		// Get payment status.
		register_rest_route(
			self::NAMESPACE,
			'/payment/status/(?P<order_id>\d+)',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'get_payment_status' ),
				'permission_callback' => array( $this, 'verify_payment_nonce' ),
				'args'                => array(
					'order_id' => array(
						'required'          => true,
						'type'              => 'integer',
						'sanitize_callback' => 'absint',
					),
				),
			)
		);

		// Create Stripe PaymentIntent from cart (for immediate payment element display).
		register_rest_route(
			self::NAMESPACE,
			'/stripe/create-cart-intent',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'create_stripe_cart_intent' ),
				'permission_callback' => array( $this, 'verify_payment_nonce' ),
				'args'                => array(
					'amount' => array(
						'required'          => true,
						'type'              => 'number',
						'sanitize_callback' => array( $this, 'sanitize_float' ),
					),
					'currency' => array(
						'required'          => false,
						'type'              => 'string',
						'default'           => 'GBP',
						'sanitize_callback' => 'sanitize_text_field',
					),
				),
			)
		);

		// Update Stripe PaymentIntent amount.
		register_rest_route(
			self::NAMESPACE,
			'/stripe/update-intent',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'update_stripe_intent' ),
				'permission_callback' => array( $this, 'verify_payment_nonce' ),
				'args'                => array(
					'payment_intent_id' => array(
						'required'          => true,
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
					),
					'amount' => array(
						'required'          => true,
						'type'              => 'number',
						'sanitize_callback' => array( $this, 'sanitize_float' ),
					),
				),
			)
		);

		// Stripe subscription endpoints.
		register_rest_route(
			self::NAMESPACE,
			'/stripe/create-subscription-intent',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'create_stripe_subscription_intent' ),
				'permission_callback' => array( $this, 'verify_payment_nonce' ),
				'args'                => array(
					'order_id' => array(
						'required'          => true,
						'type'              => 'integer',
						'sanitize_callback' => 'absint',
					),
					'email' => array(
						'required'          => true,
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_email',
					),
				),
			)
		);

		register_rest_route(
			self::NAMESPACE,
			'/stripe/confirm-subscription-setup',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'confirm_stripe_subscription_setup' ),
				'permission_callback' => array( $this, 'verify_payment_nonce' ),
				'args'                => array(
					'setup_intent_id' => array(
						'required'          => true,
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
					),
					'order_id' => array(
						'required'          => true,
						'type'              => 'integer',
						'sanitize_callback' => 'absint',
					),
				),
			)
		);

		register_rest_route(
			self::NAMESPACE,
			'/subscriptions/(?P<id>\d+)/update-payment-method',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'update_subscription_payment_method' ),
				'permission_callback' => array( $this, 'verify_payment_nonce' ),
				'args'                => array(
					'payment_method_id' => array(
						'required'          => true,
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
					),
				),
			)
		);
	}

	/**
	 * Sanitize a float value for REST API.
	 *
	 * This is needed because floatval() only accepts 1 argument,
	 * but REST API sanitize_callback receives 3 arguments.
	 *
	 * @param mixed $value The value to sanitize.
	 * @return float
	 */
	public function sanitize_float( $value ) {
		return floatval( $value );
	}

	/**
	 * Verify payment nonce for protected endpoints.
	 *
	 * For cart-based payment intents, we allow logged-out users (guests).
	 * The nonce verification ensures the request came from our checkout page.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return bool|WP_Error
	 */
	public function verify_payment_nonce( $request ) {
		$nonce = $request->get_header( 'X-GGMC-Payment-Nonce' );

		if ( empty( $nonce ) ) {
			$nonce = $request->get_param( 'nonce' );
		}

		// If no nonce provided, this might be from a cached page or script not loaded.
		if ( empty( $nonce ) ) {
			return new WP_Error(
				'rest_forbidden',
				__( 'Payment session expired. Please refresh the page.', 'ggm-commerce' ),
				array( 'status' => 403 )
			);
		}

		// wp_verify_nonce returns 1 or 2 for valid nonces, false for invalid.
		// Value of 1 means nonce is less than 12 hours old.
		// Value of 2 means nonce is between 12-24 hours old.
		$verified = wp_verify_nonce( $nonce, 'ggm_commerce_payment' );

		if ( false === $verified || 0 === $verified ) {
			// For payment endpoints, allow if REST nonce is valid instead.
			// This handles cases where the custom nonce failed but the request is still legitimate.
			$rest_nonce = $request->get_header( 'X-WP-Nonce' );
			if ( ! empty( $rest_nonce ) && wp_verify_nonce( $rest_nonce, 'wp_rest' ) ) {
				return true;
			}

			return new WP_Error(
				'rest_forbidden',
				__( 'Payment session expired. Please refresh the page.', 'ggm-commerce' ),
				array( 'status' => 403 )
			);
		}

		return true;
	}

	/**
	 * Handle Stripe webhook.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function handle_stripe_webhook( $request ) {
		$gateway = ggm_commerce_gateways()->get_gateway( 'stripe' );

		if ( ! $gateway ) {
			return new WP_REST_Response(
				array( 'error' => 'Stripe gateway not found' ),
				500
			);
		}

		try {
			$result = $gateway->handle_webhook();

			if ( is_array( $result ) && isset( $result['success'] ) ) {
				return new WP_REST_Response( $result, $result['success'] ? 200 : 400 );
			}

			return new WP_REST_Response( array( 'received' => true ), 200 );
		} catch ( Exception $e ) {
			return new WP_REST_Response(
				array( 'error' => $e->getMessage() ),
				400
			);
		}
	}

	/**
	 * Handle PayPal webhook.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function handle_paypal_webhook( $request ) {
		$gateway = ggm_commerce_gateways()->get_gateway( 'paypal' );

		if ( ! $gateway ) {
			return new WP_REST_Response(
				array( 'error' => 'PayPal gateway not found' ),
				500
			);
		}

		try {
			$result = $gateway->handle_webhook();

			if ( is_array( $result ) && isset( $result['success'] ) ) {
				return new WP_REST_Response( $result, $result['success'] ? 200 : 400 );
			}

			return new WP_REST_Response( array( 'received' => true ), 200 );
		} catch ( Exception $e ) {
			return new WP_REST_Response(
				array( 'error' => $e->getMessage() ),
				400
			);
		}
	}

	/**
	 * Create Stripe PaymentIntent.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function create_stripe_intent( $request ) {
		$gateway = ggm_commerce_gateways()->get_gateway( 'stripe' );

		if ( ! $gateway || ! $gateway->is_available() ) {
			return new WP_REST_Response(
				array(
					'success' => false,
					'error'   => __( 'Stripe gateway is not available.', 'ggm-commerce' ),
				),
				400
			);
		}

		$order_id = $request->get_param( 'order_id' );

		try {
			$result = $gateway->create_payment_intent( $order_id );
			return new WP_REST_Response( $result, $result['success'] ? 200 : 400 );
		} catch ( Exception $e ) {
			return new WP_REST_Response(
				array(
					'success' => false,
					'error'   => $e->getMessage(),
				),
				400
			);
		}
	}

	/**
	 * Confirm Stripe payment.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function confirm_stripe_payment( $request ) {
		$gateway = ggm_commerce_gateways()->get_gateway( 'stripe' );

		if ( ! $gateway || ! $gateway->is_available() ) {
			return new WP_REST_Response(
				array(
					'success' => false,
					'error'   => __( 'Stripe gateway is not available.', 'ggm-commerce' ),
				),
				400
			);
		}

		$payment_intent_id = $request->get_param( 'payment_intent_id' );
		$order_id          = intval( $request->get_param( 'order_id' ) );

		try {
			$result = $gateway->confirm_payment( $payment_intent_id, $order_id );
			return new WP_REST_Response( $result, $result['success'] ? 200 : 400 );
		} catch ( Exception $e ) {
			return new WP_REST_Response(
				array(
					'success' => false,
					'error'   => $e->getMessage(),
				),
				400
			);
		}
	}

	/**
	 * Create PayPal order.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function create_paypal_order( $request ) {
		$gateway = ggm_commerce_gateways()->get_gateway( 'paypal' );

		if ( ! $gateway || ! $gateway->is_available() ) {
			return new WP_REST_Response(
				array(
					'success' => false,
					'error'   => __( 'PayPal gateway is not available.', 'ggm-commerce' ),
				),
				400
			);
		}

		$order_id = $request->get_param( 'order_id' );

		try {
			$result = $gateway->create_paypal_order( $order_id );
			return new WP_REST_Response( $result, $result['success'] ? 200 : 400 );
		} catch ( Exception $e ) {
			return new WP_REST_Response(
				array(
					'success' => false,
					'error'   => $e->getMessage(),
				),
				400
			);
		}
	}

	/**
	 * Capture PayPal order.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function capture_paypal_order( $request ) {
		$gateway = ggm_commerce_gateways()->get_gateway( 'paypal' );

		if ( ! $gateway || ! $gateway->is_available() ) {
			return new WP_REST_Response(
				array(
					'success' => false,
					'error'   => __( 'PayPal gateway is not available.', 'ggm-commerce' ),
				),
				400
			);
		}

		$paypal_order_id = $request->get_param( 'paypal_order_id' );
		$order_id        = $request->get_param( 'order_id' );

		try {
			$result = $gateway->capture_paypal_order( $paypal_order_id, $order_id );
			return new WP_REST_Response( $result, $result['success'] ? 200 : 400 );
		} catch ( Exception $e ) {
			return new WP_REST_Response(
				array(
					'success' => false,
					'error'   => $e->getMessage(),
				),
				400
			);
		}
	}

	/**
	 * Get payment status for an order.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function get_payment_status( $request ) {
		global $wpdb;

		$order_id = $request->get_param( 'order_id' );

		$order = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT id, order_number, payment_method, payment_status, payment_transaction_id, status, total_amount
				FROM {$wpdb->prefix}ggmc_orders
				WHERE id = %d",
				$order_id
			)
		);

		if ( ! $order ) {
			return new WP_REST_Response(
				array(
					'success' => false,
					'error'   => __( 'Order not found.', 'ggm-commerce' ),
				),
				404
			);
		}

		return new WP_REST_Response(
			array(
				'success'        => true,
				'order_id'       => $order->id,
				'order_number'   => $order->order_number,
				'payment_method' => $order->payment_method,
				'payment_status' => $order->payment_status,
				'order_status'   => $order->status,
				'total'          => $order->total_amount,
			),
			200
		);
	}

	/**
	 * Create Stripe PaymentIntent from cart total.
	 *
	 * This allows the Payment Element to be displayed immediately on checkout.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function create_stripe_cart_intent( $request ) {
		$gateway = ggm_commerce_gateways()->get_gateway( 'stripe' );

		if ( ! $gateway || ! $gateway->is_available() ) {
			return new WP_REST_Response(
				array(
					'success' => false,
					'error'   => __( 'Stripe gateway is not available.', 'ggm-commerce' ),
				),
				400
			);
		}

		$amount   = $request->get_param( 'amount' );
		$currency = strtoupper( $request->get_param( 'currency' ) );

		// Validate amount.
		if ( $amount <= 0 ) {
			return new WP_REST_Response(
				array(
					'success' => false,
					'error'   => __( 'Invalid amount.', 'ggm-commerce' ),
				),
				400
			);
		}

		try {
			$result = $gateway->create_cart_payment_intent( $amount, $currency );
			return new WP_REST_Response( $result, $result['success'] ? 200 : 400 );
		} catch ( Exception $e ) {
			return new WP_REST_Response(
				array(
					'success' => false,
					'error'   => $e->getMessage(),
				),
				400
			);
		}
	}

	/**
	 * Update Stripe PaymentIntent amount.
	 *
	 * Called when cart total changes.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function update_stripe_intent( $request ) {
		$gateway = ggm_commerce_gateways()->get_gateway( 'stripe' );

		if ( ! $gateway || ! $gateway->is_available() ) {
			return new WP_REST_Response(
				array(
					'success' => false,
					'error'   => __( 'Stripe gateway is not available.', 'ggm-commerce' ),
				),
				400
			);
		}

		$payment_intent_id = $request->get_param( 'payment_intent_id' );
		$amount            = $request->get_param( 'amount' );
		$order_id          = intval( $request->get_param( 'order_id' ) );
		$order_number      = sanitize_text_field( $request->get_param( 'order_number' ) );

		// Validate amount.
		if ( $amount <= 0 ) {
			return new WP_REST_Response(
				array(
					'success' => false,
					'error'   => __( 'Invalid amount.', 'ggm-commerce' ),
				),
				400
			);
		}

		try {
			$result = $gateway->update_payment_intent( $payment_intent_id, $amount, $order_id, $order_number );
			return new WP_REST_Response( $result, $result['success'] ? 200 : 400 );
		} catch ( Exception $e ) {
			return new WP_REST_Response(
				array(
					'success' => false,
					'error'   => $e->getMessage(),
				),
				400
			);
		}
	}

	/**
	 * Create Stripe subscription intent (SetupIntent + optional PaymentIntent for sign-up fee).
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function create_stripe_subscription_intent( $request ) {
		$gateway = ggm_commerce_gateways()->get_gateway( 'stripe' );

		if ( ! $gateway || ! $gateway->is_available() ) {
			return new WP_REST_Response(
				array( 'success' => false, 'error' => __( 'Stripe gateway is not available.', 'ggm-commerce' ) ),
				400
			);
		}

		$order_id = $request->get_param( 'order_id' );
		$email    = $request->get_param( 'email' );

		try {
			// Get or create Stripe customer.
			$customer = $gateway->get_or_create_stripe_customer( $email );

			if ( is_wp_error( $customer ) ) {
				return new WP_REST_Response(
					array( 'success' => false, 'error' => $customer->get_error_message() ),
					400
				);
			}

			$customer_id = $customer['id'];

			// Create SetupIntent for saving payment method.
			$setup_intent = $gateway->create_setup_intent( $customer_id );

			if ( is_wp_error( $setup_intent ) ) {
				return new WP_REST_Response(
					array( 'success' => false, 'error' => $setup_intent->get_error_message() ),
					400
				);
			}

			// Save gateway customer ID to any subscriptions linked to this order.
			if ( class_exists( 'GGM_Commerce_Subscriptions' ) ) {
				global $wpdb;
				// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
				$wpdb->query( $wpdb->prepare(
					"UPDATE {$wpdb->prefix}ggmc_subscriptions SET gateway_customer_id = %s, payment_gateway = 'stripe' WHERE parent_order_id = %d",
					$customer_id,
					$order_id
				) );
			}

			return new WP_REST_Response(
				array(
					'success'        => true,
					'client_secret'  => $setup_intent['client_secret'],
					'setup_intent'   => $setup_intent['id'],
					'customer_id'    => $customer_id,
					'publishable_key' => $gateway->get_publishable_key(),
				),
				200
			);
		} catch ( \Exception $e ) {
			return new WP_REST_Response(
				array( 'success' => false, 'error' => $e->getMessage() ),
				400
			);
		}
	}

	/**
	 * Confirm Stripe subscription setup — saves payment method to subscription.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function confirm_stripe_subscription_setup( $request ) {
		$gateway = ggm_commerce_gateways()->get_gateway( 'stripe' );

		if ( ! $gateway || ! $gateway->is_available() ) {
			return new WP_REST_Response(
				array( 'success' => false, 'error' => __( 'Stripe gateway is not available.', 'ggm-commerce' ) ),
				400
			);
		}

		$setup_intent_id = $request->get_param( 'setup_intent_id' );
		$order_id        = $request->get_param( 'order_id' );

		try {
			// Retrieve the SetupIntent to get payment method.
			$setup_intent = $gateway->retrieve_setup_intent( $setup_intent_id );

			if ( isset( $setup_intent['error'] ) ) {
				return new WP_REST_Response(
					array( 'success' => false, 'error' => $setup_intent['error']['message'] ?? 'Failed to retrieve SetupIntent.' ),
					400
				);
			}

			$payment_method_id = $setup_intent['payment_method'] ?? '';
			$customer_id       = $setup_intent['customer'] ?? '';

			if ( empty( $payment_method_id ) ) {
				return new WP_REST_Response(
					array( 'success' => false, 'error' => 'No payment method on SetupIntent.' ),
					400
				);
			}

			// Update subscriptions linked to this order.
			if ( class_exists( 'GGM_Commerce_Subscriptions' ) ) {
				$sub_manager = GGM_Commerce_Subscriptions::instance();

				global $wpdb;
				// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
				$subscriptions = $wpdb->get_results( $wpdb->prepare(
					"SELECT id FROM {$wpdb->prefix}ggmc_subscriptions WHERE parent_order_id = %d",
					$order_id
				) );

				foreach ( $subscriptions as $sub ) {
					$sub_manager->update_subscription( $sub->id, array(
						'gateway_customer_id'  => $customer_id,
						'payment_method_token' => $payment_method_id,
						'payment_gateway'      => 'stripe',
					) );

					// Activate if pending.
					$sub_obj = $sub_manager->get_subscription( $sub->id );
					if ( $sub_obj && 'pending' === $sub_obj->status ) {
						$sub_manager->activate_subscription( $sub->id );
					}
				}
			}

			return new WP_REST_Response(
				array(
					'success'          => true,
					'payment_method'   => $payment_method_id,
					'customer_id'      => $customer_id,
				),
				200
			);
		} catch ( \Exception $e ) {
			return new WP_REST_Response(
				array( 'success' => false, 'error' => $e->getMessage() ),
				400
			);
		}
	}

	/**
	 * Update payment method for a subscription.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function update_subscription_payment_method( $request ) {
		if ( ! class_exists( 'GGM_Commerce_Subscriptions' ) ) {
			return new WP_REST_Response(
				array( 'success' => false, 'error' => 'Subscriptions not available.' ),
				400
			);
		}

		$subscription_id   = (int) $request->get_param( 'id' );
		$payment_method_id = $request->get_param( 'payment_method_id' );
		$sub_manager       = GGM_Commerce_Subscriptions::instance();
		$subscription      = $sub_manager->get_subscription( $subscription_id );

		if ( ! $subscription ) {
			return new WP_REST_Response(
				array( 'success' => false, 'error' => 'Subscription not found.' ),
				404
			);
		}

		// Only allow the subscription owner or an admin to change payment method.
		$current_user_id = get_current_user_id();
		if ( ! current_user_can( 'manage_options' ) && (int) $subscription->customer_id !== $current_user_id ) {
			return new WP_REST_Response(
				array( 'success' => false, 'error' => 'Permission denied.' ),
				403
			);
		}

		if ( 'stripe' === $subscription->payment_gateway ) {
			$gateway = ggm_commerce_gateways()->get_gateway( 'stripe' );
			if ( $gateway && ! empty( $subscription->gateway_customer_id ) ) {
				$attach_result = $gateway->attach_payment_method( $payment_method_id, $subscription->gateway_customer_id );
				if ( is_wp_error( $attach_result ) ) {
					return new WP_REST_Response(
						array( 'success' => false, 'error' => $attach_result->get_error_message() ),
						400
					);
				}
			}
		}

		$sub_manager->update_subscription( $subscription_id, array(
			'payment_method_token' => $payment_method_id,
		) );

		$sub_manager->log_event(
			$subscription_id,
			'payment_method_updated',
			'Payment method updated.',
			null,
			null,
			$current_user_id === (int) $subscription->customer_id ? 'customer' : 'admin'
		);

		return new WP_REST_Response( array( 'success' => true ), 200 );
	}

	/**
	 * Get webhook URL for a gateway.
	 *
	 * @param string $gateway_id Gateway ID.
	 * @return string
	 */
	public static function get_webhook_url( $gateway_id ) {
		return rest_url( self::NAMESPACE . '/webhooks/' . $gateway_id );
	}
}

// Initialize the REST API.
GGM_Commerce_Gateway_REST_API::instance();
