<?php
/**
 * PayPal Frontend Class.
 *
 * @package sureforms-pro
 * @since 2.4.0
 */

namespace SRFM_Pro\Inc\Business\Payments\PayPal;

use SRFM\Inc\Database\Tables\Payments;
use SRFM\Inc\Payments\Payment_Helper;
use SRFM\Inc\Payments\Stripe\Stripe_Helper;
use SRFM_Pro\Inc\Business\Payments\PayPal\Helper as PayPal_Helper;
use SRFM_Pro\Inc\Traits\Get_Instance;

// Exit if accessed directly.
defined( 'ABSPATH' ) || exit;

/**
 * PayPal Frontend.
 *
 * @since 2.4.0
 */
class Frontend {
	use Get_Instance;

	/**
	 * Constructor.
	 *
	 * @since 2.4.0
	 */
	public function __construct() {
		// Register AJAX handlers for one-time payments.
		add_action( 'wp_ajax_srfm_create_paypal_order', [ $this, 'create_paypal_order' ] );
		add_action( 'wp_ajax_nopriv_srfm_create_paypal_order', [ $this, 'create_paypal_order' ] );

		// Register AJAX handlers for subscriptions.
		add_action( 'wp_ajax_srfm_create_paypal_subscription', [ $this, 'create_paypal_subscription' ] );
		add_action( 'wp_ajax_nopriv_srfm_create_paypal_subscription', [ $this, 'create_paypal_subscription' ] );

		// Validate the payment fields.
		add_filter( 'srfm_verify_payment_value', [ $this, 'verify_payment_value' ], 10, 1 );

		// Check if PayPal is configured.
		add_filter( 'srfm_payment_gateway_configured', [ $this, 'is_paypal_configured' ], 10, 2 );
	}

	/**
	 * Check if PayPal is configured.
	 *
	 * @param bool         $is_configured Whether any payment gateway is already configured.
	 * @param array<mixed> $settings Payment settings or block data.
	 * @since 2.4.0
	 * @return bool True if PayPal is configured, false otherwise.
	 */
	public function is_paypal_configured( $is_configured, $settings ) {
		// If already configured (e.g., Stripe is connected), return true.
		if ( $is_configured ) {
			return true;
		}

		// Check if block_data is available in settings.
		if ( isset( $settings['block_data'] ) && is_array( $settings['block_data'] ) ) {
			$block_data = $settings['block_data'];

			// Check if parsed_block exists and has attributes.
			if ( isset( $block_data['parsed_block'][0]['attrs'] ) && is_array( $block_data['parsed_block'][0]['attrs'] ) ) {
				$attributes = $block_data['parsed_block'][0]['attrs'];

				// Check if paymentMethods attribute exists.
				if ( isset( $attributes['paymentMethods'] ) && is_array( $attributes['paymentMethods'] ) ) {
					// Check if 'paypal' is in the payment methods array.
					if ( in_array( 'paypal', $attributes['paymentMethods'], true ) ) {
						// PayPal is selected for this block, check if it's configured.
						return PayPal_Helper::is_paypal_connected();
					}

					// PayPal is not in the payment methods, return false.
					return false;
				}
			}
		}

		// No block_data or paymentMethods attribute, check if PayPal is connected (backward compatibility).
		return PayPal_Helper::is_paypal_connected();
	}

	/**
	 * Summary of verify_payment_value
	 *
	 * @param array<string,mixed> $args Payment value, class, block ID and form data.
	 * @since 2.4.0
	 * @return array<string,mixed> Payment response.
	 */
	public function verify_payment_value( $args ) {
		$payment_value = ! empty( $args['payment_value'] ) && is_array( $args['payment_value'] ) ? $args['payment_value'] : [];
		$class         = ! empty( $args['class'] ) && is_object( $args['class'] ) ? $args['class'] : null;
		$block_id      = ! empty( $args['block_id'] ) && is_string( $args['block_id'] ) ? $args['block_id'] : '';
		$form_data     = ! empty( $args['form_data'] ) && is_array( $args['form_data'] ) ? $args['form_data'] : [];

		if ( empty( $payment_value ) || empty( $class ) ) {
			return $args;
		}

		if ( 'paypal' === $payment_value['paymentMethod'] ) {
			$paypal_payment_type = ! empty( $payment_value['paymentType'] ) ? $payment_value['paymentType'] : '';
			if ( 'subscription' === $paypal_payment_type ) {
				$payment_response = $this->verify_and_activate_paypal_subscription( $payment_value, $block_id, $form_data, $class );
			} else {
				$payment_response = $this->verify_and_capture_paypal_payment( $payment_value, $block_id, $form_data, $class );
			}

			return $payment_response;
		}

		return $args;
	}

	/**
	 * Summary of verify_and_capture_paypal_payment
	 *
	 * @param array<string,mixed> $payment_value Payment value.
	 * @param mixed               $block_id Block ID.
	 * @param array<string,mixed> $form_data Form data.
	 * @param object              $class Class.
	 * @since 2.4.0
	 * @return array<string,mixed> Payment response.
	 */
	public function verify_and_capture_paypal_payment( $payment_value, $block_id = '', $form_data = [], $class = null ) {
		// Extract form context.
		$form_id = isset( $form_data['form-id'] ) && is_numeric( $form_data['form-id'] )
			? intval( $form_data['form-id'] ) : 0;

		// Extract customer data from payment_value.
		$customer_data  = ! empty( $payment_value['customerData'] ) && is_array( $payment_value['customerData'] )
			? $payment_value['customerData'] : [];
		$customer_name  = ! empty( $customer_data['name'] ) && is_string( $customer_data['name'] )
			? sanitize_text_field( $customer_data['name'] ) : '';
		$customer_email = ! empty( $customer_data['email'] ) && is_string( $customer_data['email'] )
			? sanitize_email( $customer_data['email'] ) : '';

		// Extract orderID from payment data.
		$order_id = ! empty( $payment_value['orderID'] ) && is_string( $payment_value['orderID'] ) ? $payment_value['orderID'] : '';

		if ( empty( $order_id ) ) {
			return [
				'error' => __( 'PayPal Order ID not found.', 'sureforms-pro' ),
			];
		}

		// Verify payment intent with comprehensive validation including form data.
		$verification_result = Payment_Helper::verify_payment_intent( $block_id, $order_id, $form_data );

		if ( false === $verification_result['valid'] ) {
			return [
				'error' => $verification_result['message'],
			];
		}

		// Get PayPal mode.
		$mode = PayPal_Helper::get_paypal_mode();

		// Verify credentials are configured.
		$client_id     = PayPal_Helper::get_paypal_client_id( $mode );
		$client_secret = PayPal_Helper::get_paypal_client_secret( $mode );

		if ( empty( $client_id ) || empty( $client_secret ) ) {
			return [
				'error' => __( 'PayPal credentials not configured.', 'sureforms-pro' ),
			];
		}

		// Capture the order using API_Payments class.
		$capture_result = API_Payments::capture_order( $order_id, [], $mode );

		// Check if API request was successful.
		if ( empty( $capture_result['success'] ) ) {
			return [
				'error' => $capture_result['message'] ?? __( 'Failed to capture PayPal payment.', 'sureforms-pro' ),
			];
		}

		// Verify capture was successful.
		if ( ! isset( $capture_result['status'] ) || 'COMPLETED' !== $capture_result['status'] ) {
			return [
				'error' => __( 'PayPal payment capture was not completed.', 'sureforms-pro' ),
			];
		}

		// Extract capture details.
		$capture_id      = '';
		$captured_amount = 0;
		$currency        = '';

		if ( isset( $capture_result['purchase_units'][0]['payments']['captures'][0] ) ) {
			$capture_details = $capture_result['purchase_units'][0]['payments']['captures'][0];
			$capture_id      = $capture_details['id'] ?? '';
			$captured_amount = isset( $capture_details['amount']['value'] ) ? floatval( $capture_details['amount']['value'] ) : 0;
			$currency        = $capture_details['amount']['currency_code'] ?? '';
		}

		// Generate customer ID for tracking.
		$customer_id = $this->generate_customer_id();

		// Prepare entry data for database.
		$entry_data = [
			'form_id'        => $form_id,
			'block_id'       => $block_id,
			'status'         => 'succeeded',
			'total_amount'   => $captured_amount,
			'currency'       => strtolower( $currency ),
			'entry_id'       => 0,
			'gateway'        => 'paypal',
			'type'           => 'payment',
			'mode'           => $mode,
			'transaction_id' => $capture_id,
			'srfm_txn_id'    => '',
			'customer_email' => $customer_email,
			'customer_name'  => $customer_name,
			'customer_id'    => $customer_id,
			'payment_data'   => [
				'payment_value'  => $payment_value,
				'capture_result' => $capture_result,
			],
		];

		// Add log entry.
		$user_id   = get_current_user_id();
		$user_info = $user_id > 0
			/* translators: %d: User ID */
			? sprintf( __( 'User ID: %d', 'sureforms-pro' ), $user_id )
			: __( 'Guest User', 'sureforms-pro' );

		$entry_data['log'] = [
			[
				'title'      => __( 'Payment Verification', 'sureforms-pro' ),
				'created_at' => current_time( 'mysql' ),
				'messages'   => [
					/* translators: %s: transaction ID */
					sprintf( __( 'Transaction ID: %s', 'sureforms-pro' ), $capture_id ),
					/* translators: %s: order ID */
					sprintf( __( 'Order ID: %s', 'sureforms-pro' ), $order_id ),
					/* translators: %s: payment gateway */
					sprintf( __( 'Payment Gateway: %s', 'sureforms-pro' ), 'PayPal' ),
					/* translators: %1$s: amount, %2$s: currency */
					sprintf( __( 'Amount: %1$s %2$s', 'sureforms-pro' ), number_format( $captured_amount, 2 ), strtoupper( $currency ) ),
					/* translators: %s: status */
					sprintf( __( 'Status: %s', 'sureforms-pro' ), $capture_result['status'] ),
					$user_info,
					/* translators: %s: mode */
					sprintf( __( 'Mode: %s', 'sureforms-pro' ), ucfirst( $mode ) ),
				],
			],
		];

		// Save to database.
		$payment_entry_id = Payments::add( $entry_data );

		if ( ! $payment_entry_id ) {
			return [
				'error' => __( 'Failed to create payment entry.', 'sureforms-pro' ),
			];
		}

		// Generate unique payment ID.
		$unique_payment_id = Stripe_Helper::generate_unique_payment_id( $payment_entry_id );
		Payments::update(
			$payment_entry_id,
			[
				'srfm_txn_id' => $unique_payment_id,
			]
		);

		// Add for entry linking.
		if ( is_object( $class ) && method_exists( $class, 'add_payment_entry_for_linking' ) ) {
			$class->add_payment_entry_for_linking(
				[
					'payment_id' => $capture_id,
					'block_id'   => $block_id,
					'form_id'    => $form_id,
				]
			);
		}

		// Clean up transient after successful verification to prevent reuse.
		Payment_Helper::delete_payment_intent_metadata( $block_id, $order_id );

		return [
			'payment_id' => is_numeric( $payment_entry_id ) ? intval( $payment_entry_id ) : 0,
		];
	}

	/**
	 * Summary of verify_and_activate_paypal_subscription
	 *
	 * @param array<string,mixed> $payment_value Payment value.
	 * @param mixed               $block_id Block ID.
	 * @param array<string,mixed> $form_data Form data.
	 * @param object              $class Class.
	 * @since 2.4.0
	 * @return array<string,mixed> Payment response.
	 */
	public function verify_and_activate_paypal_subscription( $payment_value, $block_id, $form_data, $class ) {
		// Extract form context.
		$form_id = isset( $form_data['form-id'] ) && is_numeric( $form_data['form-id'] )
			? intval( $form_data['form-id'] ) : 0;

		// Extract customer data from payment_value.
		$customer_data  = isset( $payment_value['customerData'] ) && is_array( $payment_value['customerData'] )
			? $payment_value['customerData'] : [];
		$customer_name  = ! empty( $customer_data['name'] ) && is_string( $customer_data['name'] )
			? sanitize_text_field( $customer_data['name'] ) : '';
		$customer_email = ! empty( $customer_data['email'] ) && is_string( $customer_data['email'] )
			? sanitize_email( $customer_data['email'] ) : '';

		// Extract subscriptionID from payment data.
		$subscription_id = isset( $payment_value['subscriptionID'] ) && is_string( $payment_value['subscriptionID'] ) ? $payment_value['subscriptionID'] : '';

		if ( empty( $subscription_id ) ) {
			return [
				'error' => __( 'PayPal Subscription ID not found.', 'sureforms-pro' ),
			];
		}

		// Verify payment intent was created through our system.
		$verification_result = Payment_Helper::verify_payment_intent( $block_id, $subscription_id, $form_data );

		if ( false === $verification_result['valid'] ) {
			// Payment intent not found - not created through our system.
			return [
				'error' => $verification_result['message'],
			];
		}

		// Get PayPal mode.
		$mode = PayPal_Helper::get_paypal_mode();

		// Verify credentials are configured.
		$client_id     = PayPal_Helper::get_paypal_client_id( $mode );
		$client_secret = PayPal_Helper::get_paypal_client_secret( $mode );

		if ( empty( $client_id ) || empty( $client_secret ) ) {
			return [
				'error' => __( 'PayPal credentials not configured.', 'sureforms-pro' ),
			];
		}

		// Get subscription details using API_Payments class.
		$subscription_details = API_Payments::get_subscription( $subscription_id, $mode );

		// Check if API request was successful.
		if ( empty( $subscription_details['success'] ) ) {
			return [
				'error' => $subscription_details['message'] ?? __( 'Failed to retrieve PayPal subscription.', 'sureforms-pro' ),
			];
		}

		// Verify subscription exists and is in valid state.
		if ( ! isset( $subscription_details['id'] ) ) {
			return [
				'error' => __( 'PayPal subscription not found.', 'sureforms-pro' ),
			];
		}

		$current_status               = $subscription_details['status'] ?? '';
		$current_status_to_normalized = PayPal_Helper::normalize_subscription_status( $current_status );

		// Check if subscription is already active.
		if ( 'ACTIVE' === $current_status ) {
			// Subscription is already active, extract details and return success.
			$amount   = 0;
			$currency = 'USD';

			$billing_info   = isset( $subscription_details['billing_info'] ) && is_array( $subscription_details['billing_info'] ) ? $subscription_details['billing_info'] : [];
			$last_payment   = isset( $billing_info['last_payment'] ) && is_array( $billing_info['last_payment'] ) ? $billing_info['last_payment'] : [];
			$billing_amount = isset( $last_payment['amount'] ) && is_array( $last_payment['amount'] ) ? $last_payment['amount'] : [];

			if ( isset( $billing_amount['value'] ) && isset( $billing_amount['currency_code'] ) ) {
				$amount   = ! empty( $billing_amount['value'] ) && is_numeric( $billing_amount['value'] ) ? floatval( $billing_amount['value'] ) : 0;
				$currency = ! empty( $billing_amount['currency_code'] ) && is_string( $billing_amount['currency_code'] ) ? $billing_amount['currency_code'] : 'USD';
			} elseif ( isset( $subscription_details['plan_id'] ) ) {
				// Get plan details for amount if no payment yet.
				$plan_details = $this->get_paypal_plan_details( $subscription_details['plan_id'], $mode );
				if ( $plan_details ) {
					$amount   = ! empty( $plan_details['amount'] ) && is_numeric( $plan_details['amount'] ) ? floatval( $plan_details['amount'] ) : 0;
					$currency = ! empty( $plan_details['currency'] ) && is_string( $plan_details['currency'] ) ? $plan_details['currency'] : 'USD';
				}
			}

			$currency = is_string( $currency ) ? strtolower( $currency ) : 'usd';

			// Generate customer ID for tracking.
			$customer_id = $this->generate_customer_id();

			// Prepare entry data for database.
			// IMPORTANT: For PayPal subscriptions:
			// - subscription_id: Stores the PayPal subscription ID (I-2.4.0)
			// - transaction_id: Stores the capture_id from the actual payment transaction (for refunds)
			// If capture_id is not available yet (subscription just activated), transaction_id will be empty
			// and will be populated later via webhook when the first payment completes.
			$entry_data = [
				'form_id'             => $form_id,
				'block_id'            => $block_id,
				'status'              => 'active',
				'total_amount'        => $amount,
				'currency'            => $currency,
				'entry_id'            => 0,
				'gateway'             => 'paypal',
				'type'                => 'subscription',
				'mode'                => $mode,
				'transaction_id'      => '', // Store capture_id here for refunds.
				'subscription_id'     => $subscription_id, // Store subscription_id separately.
				'subscription_status' => $current_status_to_normalized,
				'srfm_txn_id'         => '',
				'customer_email'      => $customer_email,
				'customer_name'       => $customer_name,
				'customer_id'         => $customer_id,
				'payment_data'        => [
					'payment_value'        => $payment_value,
					'subscription_details' => $subscription_details,
				],
			];

			// Add log entry.
			$user_id   = get_current_user_id();
			$user_info = $user_id > 0
				/* translators: %d: User ID */
				? sprintf( __( 'User ID: %d', 'sureforms-pro' ), $user_id )
				: __( 'Guest User', 'sureforms-pro' );

			$entry_data['log'] = [
				[
					'title'      => __( 'Subscription Verification', 'sureforms-pro' ),
					'created_at' => current_time( 'mysql' ),
					'messages'   => [
						/* translators: %s: subscription ID */
						sprintf( __( 'Subscription ID: %s', 'sureforms-pro' ), $subscription_id ),
						/* translators: %s: payment gateway */
						sprintf( __( 'Payment Gateway: %s', 'sureforms-pro' ), 'PayPal' ),
						/* translators: %1$s: amount, %2$s: currency */
						sprintf( __( 'Amount: %1$s %2$s', 'sureforms-pro' ), number_format( $amount, 2 ), $currency ),
						/* translators: %s: status */
						sprintf( __( 'Status: %s', 'sureforms-pro' ), $current_status_to_normalized ),
						$user_info,
						/* translators: %s: mode */
						sprintf( __( 'Mode: %s', 'sureforms-pro' ), ucfirst( $mode ) ),
					],
				],
			];

			// Save to database.
			$payment_entry_id = Payments::add( $entry_data );

			if ( ! $payment_entry_id ) {
				return [
					'error' => __( 'Failed to create payment entry.', 'sureforms-pro' ),
				];
			}

			// Generate unique payment ID.
			$unique_payment_id = Stripe_Helper::generate_unique_payment_id( $payment_entry_id );
			Payments::update( $payment_entry_id, [ 'srfm_txn_id' => $unique_payment_id ] );

			// Add for entry linking.
			if ( is_object( $class ) && method_exists( $class, 'add_payment_entry_for_linking' ) ) {
				$class->add_payment_entry_for_linking(
					[
						'payment_id' => $subscription_id,
						'block_id'   => $block_id,
						'form_id'    => $form_id,
					]
				);
			}

			// Clean up transient after successful verification to prevent reuse.
			Payment_Helper::delete_payment_intent_metadata( $block_id, $subscription_id );

			return [
				'payment_id' => is_numeric( $payment_entry_id ) ? intval( $payment_entry_id ) : 0,
			];
		}

		// Step 3: Activate subscription if it's in APPROVAL_PENDING or APPROVED state.
		if ( in_array( $current_status, [ 'APPROVAL_PENDING', 'APPROVED' ], true ) ) {
			$activation_data = [
				'reason' => __( 'Form submitted and verified successfully by SureForms', 'sureforms-pro' ),
			];

			// Activate subscription using Client trait.
			$activate_response = Client::request( "v1/billing/subscriptions/{$subscription_id}/activate", $activation_data, 'POST', $mode );

			if ( empty( $activate_response['success'] ) ) {
				return [
					'error' => $activate_response['message'] ?? __( 'Failed to activate PayPal subscription.', 'sureforms-pro' ),
				];
			}

			// Activation successful, get updated subscription details.
			$updated_subscription = API_Payments::get_subscription( $subscription_id, $mode );

			if ( empty( $updated_subscription['success'] ) ) {
				return [
					'error' => $updated_subscription['message'] ?? __( 'Failed to retrieve updated subscription.', 'sureforms-pro' ),
				];
			}

			// Extract subscription details for return.
			$amount   = 0;
			$currency = 'USD';

			$billing_info   = isset( $updated_subscription['billing_info'] ) && is_array( $updated_subscription['billing_info'] ) ? $updated_subscription['billing_info'] : [];
			$last_payment   = isset( $billing_info['last_payment'] ) && is_array( $billing_info['last_payment'] ) ? $billing_info['last_payment'] : [];
			$billing_amount = isset( $last_payment['amount'] ) && is_array( $last_payment['amount'] ) ? $last_payment['amount'] : [];

			if ( isset( $billing_amount['value'] ) && isset( $billing_amount['currency_code'] ) ) {
				$amount   = ! empty( $billing_amount['value'] ) && is_numeric( $billing_amount['value'] ) ? floatval( $billing_amount['value'] ) : 0;
				$currency = ! empty( $billing_amount['currency_code'] ) && is_string( $billing_amount['currency_code'] ) ? $billing_amount['currency_code'] : 'USD';
			} elseif ( isset( $updated_subscription['plan_id'] ) ) {
				// Get plan details for amount.
				$plan_details = $this->get_paypal_plan_details( $updated_subscription['plan_id'], $mode );
				if ( $plan_details ) {
					$amount   = ! empty( $plan_details['amount'] ) && is_numeric( $plan_details['amount'] ) ? floatval( $plan_details['amount'] ) : 0;
					$currency = ! empty( $plan_details['currency'] ) && is_string( $plan_details['currency'] ) ? $plan_details['currency'] : 'USD';
				}
			}

			$currency = is_string( $currency ) ? strtolower( $currency ) : 'usd';

			// Generate customer ID for tracking.
			$customer_id = $this->generate_customer_id();

			// Prepare entry data for database.
			// IMPORTANT: For PayPal subscriptions:
			// - subscription_id: Stores the PayPal subscription ID (I-2.4.0)
			// - transaction_id: Stores the capture_id from the actual payment transaction (for refunds)
			// If capture_id is not available yet (subscription just activated), transaction_id will be empty
			// and will be populated later via webhook when the first payment completes.
			$entry_data = [
				'form_id'             => $form_id,
				'block_id'            => $block_id,
				'status'              => 'active',
				'total_amount'        => $amount,
				'currency'            => $currency,
				'entry_id'            => 0,
				'gateway'             => 'paypal',
				'type'                => 'subscription',
				'mode'                => $mode,
				'transaction_id'      => '', // Store capture_id here for refunds.
				'subscription_id'     => $subscription_id, // Store subscription_id separately.
				'subscription_status' => $current_status_to_normalized,
				'srfm_txn_id'         => '',
				'customer_email'      => $customer_email,
				'customer_name'       => $customer_name,
				'customer_id'         => $customer_id,
				'payment_data'        => [
					'payment_value'        => $payment_value,
					'subscription_details' => $updated_subscription,
				],
			];

			// Add log entry.
			$user_id   = get_current_user_id();
			$user_info = $user_id > 0
				/* translators: %d: User ID */
				? sprintf( __( 'User ID: %d', 'sureforms-pro' ), $user_id )
				: __( 'Guest User', 'sureforms-pro' );

			$entry_data['log'] = [
				[
					'title'      => __( 'Subscription Activation', 'sureforms-pro' ),
					'created_at' => current_time( 'mysql' ),
					'messages'   => [
						/* translators: %s: subscription ID */
						sprintf( __( 'Subscription ID: %s', 'sureforms-pro' ), $subscription_id ),
						/* translators: %s: payment gateway */
						sprintf( __( 'Payment Gateway: %s', 'sureforms-pro' ), 'PayPal' ),
						/* translators: %1$s: amount, %2$s: currency */
						sprintf( __( 'Amount: %1$s %2$s', 'sureforms-pro' ), number_format( $amount, 2 ), $currency ),
						/* translators: %s: status */
						sprintf( __( 'Status: %s', 'sureforms-pro' ), 'ACTIVE' ),
						$user_info,
						/* translators: %s: mode */
						sprintf( __( 'Mode: %s', 'sureforms-pro' ), ucfirst( $mode ) ),
						__( 'Subscription was activated successfully.', 'sureforms-pro' ),
					],
				],
			];

			// Save to database.
			$payment_entry_id = Payments::add( $entry_data );

			if ( ! $payment_entry_id ) {
				return [
					'error' => __( 'Failed to create payment entry.', 'sureforms-pro' ),
				];
			}

			// Generate unique payment ID.
			$unique_payment_id = Stripe_Helper::generate_unique_payment_id( $payment_entry_id );
			Payments::update(
				$payment_entry_id,
				[
					'srfm_txn_id'            => $unique_payment_id,
					'parent_subscription_id' => $payment_entry_id,
				]
			);

			// Add for entry linking.
			if ( is_object( $class ) && method_exists( $class, 'add_payment_entry_for_linking' ) ) {
				$class->add_payment_entry_for_linking(
					[
						'subscription_id' => $subscription_id,
						'block_id'        => $block_id,
						'form_id'         => $form_id,
					]
				);
			}

			// Clean up transient after successful verification to prevent reuse.
			Payment_Helper::delete_payment_intent_metadata( $block_id, $subscription_id );

			return [
				'payment_id' => is_numeric( $payment_entry_id ) ? intval( $payment_entry_id ) : 0,
			];
		}

		// Subscription is in invalid state.
		return [
			'error' => sprintf(
				/* translators: %s: subscription status */
				__( 'PayPal subscription is in invalid state: %s', 'sureforms-pro' ),
				$current_status
			),
		];
	}

	/**
	 * Create PayPal order for one-time payment.
	 *
	 * AJAX handler.
	 *
	 * @since 2.4.0
	 * @return void
	 */
	public function create_paypal_order() {
		// Verify nonce.
		$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
		if ( ! wp_verify_nonce( $nonce, 'srfm_paypal_payment_nonce_frontend' ) ) {
			wp_send_json_error(
				[
					'message' => __( 'Security check failed.', 'sureforms-pro' ),
				]
			);
		}

		// Get request data.
		$amount         = isset( $_POST['amount'] ) ? floatval( $_POST['amount'] ) : 0;
		$currency       = isset( $_POST['currency'] ) ? sanitize_text_field( wp_unslash( $_POST['currency'] ) ) : 'USD';
		$description    = isset( $_POST['description'] ) ? sanitize_text_field( wp_unslash( $_POST['description'] ) ) : 'SureForms Payment';
		$customer_name  = isset( $_POST['customer_name'] ) ? sanitize_text_field( wp_unslash( $_POST['customer_name'] ) ) : '';
		$customer_email = isset( $_POST['customer_email'] ) ? sanitize_email( wp_unslash( $_POST['customer_email'] ) ) : '';
		$block_id       = isset( $_POST['block_id'] ) ? sanitize_text_field( wp_unslash( $_POST['block_id'] ) ) : '';
		$form_id        = isset( $_POST['form_id'] ) ? intval( $_POST['form_id'] ) : 0;

		// Validate amount.
		if ( $amount <= 0 ) {
			wp_send_json_error(
				[
					'message' => __( 'Invalid payment amount.', 'sureforms-pro' ),
				]
			);
		}

		// Validate payment amount against stored form configuration.
		if ( $form_id > 0 && ! empty( $block_id ) ) {
			// Validate amount in decimal format (PayPal uses major currency units).
			// For USD: $100.00 stays as 100.00, For JPY: ¥10000 stays as 10000.
			$validation_result = Payment_Helper::validate_payment_amount( $amount, $currency, $form_id, $block_id );
			if ( ! $validation_result['valid'] ) {
				wp_send_json_error(
					[
						'message' => $validation_result['message'],
					]
				);
			}
		}

		$item_total = $amount;

		// Format amount based on currency type (zero-decimal vs standard).
		$formatted_amount = PayPal_Helper::format_amount_for_paypal( $item_total, $currency );

		// Build order data.
		$order_data = [
			'intent'              => 'CAPTURE',
			'purchase_units'      => [
				[
					'reference_id' => 'default',
					'description'  => $description,
					'amount'       => [
						'currency_code' => strtoupper( $currency ),
						'value'         => $formatted_amount,
						'breakdown'     => [
							'item_total' => [
								'currency_code' => strtoupper( $currency ),
								'value'         => $formatted_amount,
							],
						],
					],
				],
			],
			'application_context' => [
				'brand_name'          => get_bloginfo( 'name' ),
				'user_action'         => 'PAY_NOW',
				'shipping_preference' => 'NO_SHIPPING',
			],
		];

		// Add payer information if available.
		if ( ! empty( $customer_email ) ) {
			$order_data['payer'] = [
				'email_address' => $customer_email,
			];

			if ( ! empty( $customer_name ) ) {
				$order_data['payer']['name'] = [
					'given_name' => $customer_name,
				];
			}
		}

		// Get PayPal mode and verify credentials.
		$mode          = PayPal_Helper::get_paypal_mode();
		$client_id     = PayPal_Helper::get_paypal_client_id();
		$client_secret = PayPal_Helper::get_paypal_client_secret();

		if ( empty( $client_id ) || empty( $client_secret ) ) {
			wp_send_json_error(
				[
					'message' => __( 'PayPal credentials not configured.', 'sureforms-pro' ),
				]
			);
		}

		// Create order using API_Payments class.
		$order_result = API_Payments::create_order( $order_data, $mode );

		// Check if API request was successful.
		if ( empty( $order_result['success'] ) ) {
			$get_issue         = isset( $order_result['details'] ) && is_array( $order_result['details'] ) ? $order_result['details'] : [];
			$get_issue_code    = isset( $get_issue[0] ) && is_array( $get_issue[0] ) && isset( $get_issue[0]['issue'] ) ? $get_issue[0]['issue'] : '';
			$get_default_error = isset( $order_result['message'] ) && is_string( $order_result['message'] ) ? $order_result['message'] : __( 'An unexpected error occurred. Please try again.', 'sureforms-pro' );
			$get_error_message = PayPal_Helper::get_error_messages( $get_issue_code, $get_default_error );

			wp_send_json_error(
				[
					'message' => $get_error_message,
				]
			);
		}

		// Return order ID to frontend.
		if ( isset( $order_result['id'] ) ) {
			$order_id = $order_result['id'];

			// Store payment intent metadata in transient for verification.
				Payment_Helper::store_payment_intent_metadata(
					$block_id,
					$order_id,
					[
						'form_id'  => $form_id,
						'block_id' => $block_id,
						'amount'   => $formatted_amount,
						'currency' => strtolower( $currency ),
					]
				);

			wp_send_json_success(
				[
					'orderID' => $order_id,
				]
			);
		}

		wp_send_json_error(
			[
				'message' => __( 'Failed to create PayPal order.', 'sureforms-pro' ),
			]
		);
	}

	/**
	 * Create PayPal subscription.
	 *
	 * AJAX handler.
	 *
	 * @since 2.4.0
	 * @return void
	 */
	public function create_paypal_subscription() {
		// Verify nonce.
		$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
		if ( ! wp_verify_nonce( $nonce, 'srfm_paypal_payment_nonce_frontend' ) ) {
			wp_send_json_error(
				[
					'message' => __( 'Security check failed.', 'sureforms-pro' ),
				]
			);
		}

		// Get request data.
		$amount         = isset( $_POST['amount'] ) ? floatval( $_POST['amount'] ) : 0;
		$currency       = isset( $_POST['currency'] ) ? sanitize_text_field( wp_unslash( $_POST['currency'] ) ) : 'USD';
		$plan_name      = isset( $_POST['plan_name'] ) ? sanitize_text_field( wp_unslash( $_POST['plan_name'] ) ) : 'Subscription Plan';
		$interval       = isset( $_POST['interval'] ) ? sanitize_text_field( wp_unslash( $_POST['interval'] ) ) : 'month';
		$billing_cycles = isset( $_POST['billing_cycles'] ) ? sanitize_text_field( wp_unslash( $_POST['billing_cycles'] ) ) : 'ongoing';
		$customer_name  = isset( $_POST['customer_name'] ) ? sanitize_text_field( wp_unslash( $_POST['customer_name'] ) ) : '';
		$customer_email = isset( $_POST['customer_email'] ) ? sanitize_email( wp_unslash( $_POST['customer_email'] ) ) : '';
		$block_id       = isset( $_POST['block_id'] ) ? sanitize_text_field( wp_unslash( $_POST['block_id'] ) ) : '';
		$form_id        = isset( $_POST['form_id'] ) ? intval( $_POST['form_id'] ) : 0;

		// Validate amount.
		if ( $amount <= 0 ) {
			wp_send_json_error(
				[
					'message' => __( 'Invalid subscription amount.', 'sureforms-pro' ),
				]
			);
		}

		// Validate payment amount against stored form configuration.
		if ( $form_id > 0 && ! empty( $block_id ) ) {
			// Validate amount in decimal format (PayPal uses major currency units).
			// For USD: $100.00 stays as 100.00, For JPY: ¥10000 stays as 10000.
			$validation_result = Payment_Helper::validate_payment_amount( $amount, $currency, $form_id, $block_id );
			if ( ! $validation_result['valid'] ) {
				wp_send_json_error(
					[
						'message' => $validation_result['message'],
					]
				);
			}
		}

		// Map interval to PayPal interval unit.
		$interval_mapping = [
			'day'     => 'DAY',
			'week'    => 'WEEK',
			'month'   => 'MONTH',
			'quarter' => 'MONTH',
			'year'    => 'YEAR',
		];

		$paypal_interval = $interval_mapping[ $interval ] ?? 'MONTH';
		$interval_count  = 'quarter' === $interval ? 3 : 1;
		$total_cycles    = 'ongoing' === $billing_cycles ? 0 : intval( $billing_cycles );

		// Get PayPal mode and verify credentials.
		$mode          = PayPal_Helper::get_paypal_mode();
		$client_id     = PayPal_Helper::get_paypal_client_id();
		$client_secret = PayPal_Helper::get_paypal_client_secret();

		if ( empty( $client_id ) || empty( $client_secret ) ) {
			wp_send_json_error(
				[
					'message' => __( 'PayPal credentials not configured.', 'sureforms-pro' ),
				]
			);
		}

		// Step 1: Create product using Client trait.
		$product_data = [
			'id'          => 'SUREFORMS_SUBSCRIPTION_' . time(),
			'name'        => $plan_name,
			'description' => $plan_name,
			'type'        => 'SERVICE',
			'category'    => 'SOFTWARE',
		];

		$product_result = Client::request( 'v1/catalogs/products', $product_data, 'POST', $mode );

		if ( empty( $product_result['success'] ) || ! isset( $product_result['id'] ) ) {
			wp_send_json_error(
				[
					'message' => $product_result['message'] ?? __( 'Failed to create PayPal product.', 'sureforms-pro' ),
				]
			);
		}

		$product_id       = $product_result['id'];
		$amount_formatted = PayPal_Helper::format_amount_for_paypal( $amount, $currency );

		// Step 2: Create billing plan using Client trait.
		$plan_data = [
			'product_id'          => $product_id,
			'name'                => $plan_name,
			'description'         => $plan_name,
			'status'              => 'ACTIVE',
			'billing_cycles'      => [
				[
					'frequency'      => [
						'interval_unit'  => $paypal_interval,
						'interval_count' => $interval_count,
					],
					'tenure_type'    => 'REGULAR',
					'sequence'       => 1,
					'total_cycles'   => $total_cycles,
					'pricing_scheme' => [
						'fixed_price' => [
							'value'         => $amount_formatted,
							'currency_code' => strtoupper( $currency ),
						],
					],
				],
			],
			'payment_preferences' => [
				'auto_bill_outstanding'     => true,
				'setup_fee_failure_action'  => 'CONTINUE',
				'payment_failure_threshold' => 3,
			],
		];

		$plan_result = Client::request( 'v1/billing/plans', $plan_data, 'POST', $mode );

		if ( empty( $plan_result['success'] ) || ! isset( $plan_result['id'] ) ) {

			// Check if API request was successful.
			$get_issue         = isset( $plan_result['details'] ) && is_array( $plan_result['details'] ) ? $plan_result['details'] : [];
			$get_issue_code    = isset( $get_issue[0] ) && is_array( $get_issue[0] ) && isset( $get_issue[0]['issue'] ) ? $get_issue[0]['issue'] : '';
			$get_default_error = isset( $plan_result['message'] ) && is_string( $plan_result['message'] ) ? $plan_result['message'] : __( 'An unexpected error occurred. Please try again.', 'sureforms-pro' );
			$get_error_message = PayPal_Helper::get_error_messages( $get_issue_code, $get_default_error );

			wp_send_json_error(
				[
					'message' => $get_error_message,
				]
			);
		}

		$plan_id = $plan_result['id'];

		// Step 3: Create subscription using API_Payments class.
		$subscription_data = [
			'plan_id'             => $plan_id,
			'application_context' => [
				'brand_name'          => get_bloginfo( 'name' ),
				'shipping_preference' => 'NO_SHIPPING',
				'user_action'         => 'CONTINUE',
			],
		];

		// Add subscriber information if available.
		if ( ! empty( $customer_email ) ) {
			$subscription_data['subscriber'] = [
				'email_address' => $customer_email,
			];

			if ( ! empty( $customer_name ) ) {
				$subscription_data['subscriber']['name'] = [
					'given_name' => $customer_name,
				];
			}
		}

		$subscription_result = API_Payments::create_subscription( $subscription_data, $mode );

		if ( empty( $subscription_result['success'] ) || ! isset( $subscription_result['id'] ) ) {
			wp_send_json_error(
				[
					'message' => $subscription_result['message'] ?? __( 'Failed to create PayPal subscription.', 'sureforms-pro' ),
				]
			);
		}

		// Extract approval URL from links.
		$approval_url = '';
		if ( isset( $subscription_result['links'] ) && is_array( $subscription_result['links'] ) ) {
			foreach ( $subscription_result['links'] as $link ) {
				if ( isset( $link['rel'] ) && 'approve' === $link['rel'] ) {
					$approval_url = $link['href'] ?? '';
					break;
				}
			}
		}

		$subscription_id = $subscription_result['id'];

		// Store payment intent metadata in transient for verification.
		Payment_Helper::store_payment_intent_metadata(
			$block_id,
			$subscription_id,
			[
				'form_id'         => $form_id,
				'block_id'        => $block_id,
				'amount'          => $amount_formatted,
				'currency'        => strtolower( $currency ),
				'subscription_id' => $subscription_id,
			]
		);

		wp_send_json_success(
			[
				'subscriptionID' => $subscription_id,
				'planID'         => $plan_id,
				'status'         => $subscription_result['status'] ?? 'APPROVAL_PENDING',
				'create_time'    => $subscription_result['create_time'] ?? gmdate( 'c' ),
				'approval_url'   => $approval_url,
			]
		);
	}

	/**
	 * Summary of get_paypal_plan_details
	 *
	 * @param string $plan_id PayPal plan ID.
	 * @param string $mode PayPal mode.
	 * @since 2.4.0
	 * @return array<string,mixed>|null Plan details.
	 */
	private function get_paypal_plan_details( $plan_id, $mode = null ) {
		// Get plan details using Client trait.
		$plan_data = Client::request( "v1/billing/plans/{$plan_id}", [], 'GET', $mode );

		// Check if request was successful.
		if ( empty( $plan_data['success'] ) ) {
			return null;
		}

		// Extract pricing from billing cycles.
		if ( isset( $plan_data['billing_cycles'][0]['pricing_scheme']['fixed_price'] ) ) {
			$fixed_price = $plan_data['billing_cycles'][0]['pricing_scheme']['fixed_price'];
			return [
				'amount'   => $fixed_price['value'],
				'currency' => $fixed_price['currency_code'],
			];
		}

		return null;
	}

	/**
	 * Get user IP address
	 *
	 * @since 2.4.0
	 * @return string User IP address.
	 */
	private function get_user_ip() {
		// Check for various IP address headers.
		$ip_keys = [ 'HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP', 'HTTP_CLIENT_IP', 'REMOTE_ADDR' ];

		foreach ( $ip_keys as $key ) {
			if ( ! empty( $_SERVER[ $key ] ) ) {
				$ip = sanitize_text_field( wp_unslash( $_SERVER[ $key ] ) );
				// Handle comma-separated IPs (from proxies).
				if ( strpos( $ip, ',' ) !== false ) {
					$ip = trim( explode( ',', $ip )[0] );
				}
				if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) ) {
					return $ip;
				}
			}
		}

		// Fallback to REMOTE_ADDR without filters (might be local IP).
		if ( ! empty( $_SERVER['REMOTE_ADDR'] ) ) {
			$ip = sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) );
			if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) {
				return $ip;
			}
		}

		return '0.0.0.0';
	}

	/**
	 * Generate customer ID for PayPal payments
	 *
	 * For logged-in users: Returns 'wp_user_{user_id}'
	 * For guest users: Returns 'guest_{hashed_ip}'
	 *
	 * @since 2.4.0
	 * @return string Customer ID.
	 */
	private function generate_customer_id() {
		$user_id = get_current_user_id();

		if ( $user_id > 0 ) {
			// Logged-in user: use WordPress user ID.
			return 'wp_user_' . $user_id;
		}

		// Guest user: use hashed IP address.
		$ip_address = $this->get_user_ip();
		$hashed_ip  = md5( $ip_address );

		return 'guest_' . $hashed_ip;
	}

}
