<?php
/**
 * Stripe PaymentIntent
 *
 * @package SimplePay\Core\Payments\PaymentIntent
 * @copyright Copyright (c) 2022, Sandhills Development, LLC
 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
 * @since 3.6.0
 */

namespace SimplePay\Core\Payments\PaymentIntent;

use SimplePay\Core\API\Customers;
use SimplePay\Core\API\PaymentIntents;
use SimplePay\Core\Legacy;
use SimplePay\Vendor\Stripe\Coupon;
use SimplePay\Pro\Payment_Methods;

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

/**
 * Retrieves a PaymentIntent.
 *
 * @since 3.8.0
 *
 * @param string|array $payment_intent Payment Intent ID or {
 *   Arguments used to retrieve a PaymentIntent.
 *
 *   @type string $id Payment Intent ID.
 * }
 * @param array        $api_request_args {
 *   Additional request arguments to send to the Stripe API when making a request.
 *
 *   @type string $api_key API Secret Key to use.
 * }
 * @return \SimplePay\Vendor\Stripe\PaymentIntent
 */
function retrieve( $payment_intent, $api_request_args = array() ) {
	_deprecated_function(
		__FUNCTION__,
		'4.7.0',
		'\SimplePay\Core\API\PaymentIntents\retrieve'
	);

	return PaymentIntents\retrieve( $payment_intent, $api_request_args );
}

/**
 * Retrieves PaymentIntents.
 *
 * @since 3.8.0
 *
 * @param array $payment_intents Optional arguments used when listing PaymentIntents.
 * @param array $api_request_args {
 *   Additional request arguments to send to the Stripe API when making a request.
 *
 *   @type string $api_key API Secret Key to use.
 * }
 * @return object
 */
function all( $payment_intents = array(), $api_request_args = array() ) {
	_deprecated_function(
		__FUNCTION__,
		'4.7.0',
		'\SimplePay\Core\API\PaymentIntents\all'
	);

	return PaymentIntents\all( $payment_intents, $api_request_args );
}

/**
 * Creates a PaymentIntent.
 *
 * @since 3.6.0
 *
 * @param array $payment_intent_args Arguments used to create a PaymentIntent.
 * @param array $api_request_args {
 *   Additional request arguments to send to the Stripe API when making a request.
 *
 *   @type string $api_key API Secret Key to use.
 * }
 * @return \SimplePay\Vendor\Stripe\PaymentIntent
 */
function create( $payment_intent_args, $api_request_args = array() ) {
	_deprecated_function(
		__FUNCTION__,
		'4.7.0',
		'\SimplePay\Core\API\PaymentIntents\create'
	);

	return PaymentIntents\create( $payment_intent_args, $api_request_args );
}

/**
 * Uses the current payment form request to generate arguments for a PaymentIntent.
 *
 * @param SimplePay\Core\Abstracts\Form $form Form instance.
 * @param array                         $form_data Form data generated by the client.
 * @param array                         $form_values Values of named fields in the payment form.
 * @param int                           $customer_id Stripe Customer ID.
 * @throws \Exception If unable to locate price.
 * @return array
 */
function get_args_from_payment_form_request(
	$form,
	$form_data,
	$form_values,
	$customer_id
) {
	// Retrieve price option.
	$price = simpay_payment_form_prices_get_price_by_id(
		$form,
		$form_data['price']['id']
	);

	if ( false === $price ) {
		throw new \Exception(
			__( 'Unable to locate payment form price.', 'stripe' )
		);
	}

	$quantity = isset( $form_values['simpay_quantity'] )
		? intval( $form_values['simpay_quantity'] )
		: 1;

	if ( false === $price->is_in_stock( $quantity ) ) {
		throw new \Exception(
			__( 'Sorry, this item is no longer in stock.', 'stripe' )
		);
	}

	$payment_args = get_payment_args_from_form_request(
		$form,
		$form_data,
		$form_values,
		$customer_id,
		$price
	);

	$amount   = $payment_args['amount'];
	$metadata = array(
		'simpay_form_id'         => $form->id,
		'simpay_price_instances' => sprintf(
			'%s:%d',
			$price->instance_id,
			$quantity
		),
	);

	// Add fee recovery information if needed.
	if ( 0 !== $payment_args['fee_recovery'] ) {
		// Update amount.
		$amount = $payment_args['amount'] + $payment_args['fee_recovery'];

		// Add metadata for easier Smart Tag usage.
		$metadata['simpay_fee_recovery_unit_amount'] = $payment_args['fee_recovery'];
	}

	$paymentintent_args = array(
		'amount'   => $amount,
		'currency' => $payment_args['currency'],
		'metadata' => array_merge(
			$metadata,
			Legacy\Hooks\simpay_payment_metadata(
				$form,
				$form_data,
				$form_values,
				$customer_id
			)
		),
	);

	// Use price option label if one is set.
	if ( null !== $price->label ) {
		$paymentintent_args['description'] = $price->get_display_label();

		// Fall back to Payment Form title if set.
		// This is a change in behavior in 4.1, but matches the Stripe Checkout
		// usage that falls back to the Product title (Payment Form title).
	} else {
		if ( ! empty( $form->company_name ) ) {
			$paymentintent_args['description'] = $form->company_name;
		}
	}

	if ( ! empty( $form->statement_descriptor ) ) {
		$paymentintent_args['statement_descriptor'] = $form->statement_descriptor;
	}

	// Legacy filter.
	$paymentintent_args = Legacy\Hooks\simpay_stripe_charge_args(
		$paymentintent_args,
		$form,
		$form_values
	);

	/**
	 * Filters arguments used to create a PaymentIntent from a payment form request.
	 *
	 * @since 3.6.0
	 *
	 * @param array                         $paymentintent_args Arguments for PaymentIntent.
	 * @param SimplePay\Core\Abstracts\Form $form Form instance.
	 * @param array                         $form_data Form data generated by the client.
	 * @param array                         $form_values Values of named fields in the payment form.
	 * @param int                           $customer_id Stripe Customer ID.
	 * @return array
	 */
	$paymentintent_args = apply_filters(
		'simpay_get_paymentintent_args_from_payment_form_request',
		$paymentintent_args,
		$form,
		$form_data,
		$form_values,
		$customer_id
	);

	return $paymentintent_args;
}

/**
 * Uses the current payment form request to generate relevant arguments for a payment.
 *
 * This currently includes `amount` and `currency`.
 *
 * @since 4.1.0
 *
 * @param SimplePay\Core\Abstracts\Form           $form Form instance.
 * @param array                                   $form_data Form data generated by the client.
 * @param array                                   $form_values Values of named fields in the Payment Porm.
 * @param string|null                             $customer_id Stripe Customer ID.
 * @param \SimplePay\Core\PaymentForm\PriceOption $price Price option.
 * @return array
 */
function get_payment_args_from_form_request(
	$form,
	$form_data,
	$form_values,
	$customer_id,
	$price
) {
	// Custom amount. Verify minimum amount.
	if ( false === simpay_payment_form_prices_is_defined_price( $price->id ) ) {
		// Ensure custom amount meets minimum requirement.
		$unit_amount = $form_data['customAmount'];

		if ( $unit_amount < $price->unit_amount_min ) {
			$unit_amount = $price->unit_amount_min;
		}
	} else {
		$unit_amount = $price->unit_amount;
	}

	// Backwards compatibility amount filter.
	if ( has_filter( 'simpay_form_' . $form->id . '_amount' ) ) {
		$unit_amount = simpay_get_filtered(
			'amount',
			simpay_convert_amount_to_dollars( $unit_amount ),
			$form->id
		);

		$unit_amount = simpay_convert_amount_to_cents( $unit_amount );
	}

	$currency = $price->currency;

	// Backwards compatibility currency filter.
	if ( has_filter( 'simpay_form_' . $form->id . '_currency' ) ) {
		$currency = simpay_get_filtered(
			'currency',
			strtolower( $currency ),
			$form->id
		);
	}

	// Calculate quantity.
	$quantity = isset( $form_values['simpay_quantity'] )
		? intval( $form_values['simpay_quantity'] )
		: 1;

	$unit_amount = $unit_amount * $quantity;

	// Calculate coupon discount.
	if (
		isset( $form_data['coupon'] ) &&
		false !== $form_data['coupon'] &&
		null !== $customer_id
	) {
		// Validate the coupon by ensuring it is attached to the Customer.
		$customer = Customers\retrieve(
			$customer_id,
			$form->get_api_request_args()
		);

		$coupon = $customer->discount ? $customer->discount->coupon : false;

		if ( $coupon instanceof Coupon ) {
			if ( $coupon->amount_off ) {
				$unit_amount = $unit_amount - $coupon->amount_off;
			} else {
				$percent_off = $coupon->percent_off / 100;
				$unit_amount = $unit_amount - ( $unit_amount * $percent_off );
			}

			$unit_amount = round( $unit_amount );
		}
	}

	// Add taxes if available. Done in Lite to avoid introducing a filter.
	$tax_status = get_post_meta( $form->id, '_tax_status', true );

	if (
		function_exists( 'simpay_get_payment_form_tax_rates' ) &&
		(
			empty( $tax_status ) ||
			'fixed-global' === $tax_status
		)
	) {

		// Legacy tax percentage.
		if ( has_filter( 'simpay_form_' . $form->id . '_tax_percent' ) ) {
			$tax_percent = floatval(
				simpay_get_filtered(
					'tax_percent',
					0,
					$form->id
				)
			);

			if ( 0 !== $tax_percent ) {
				$unit_amount = round(
					$unit_amount + ( $unit_amount * ( $tax_percent / 100 ) )
				);
			}

			// Tax rates.
		} else {
			$tax_rates = simpay_get_payment_form_tax_rates( $form );

			if ( ! empty( $tax_rates ) ) {
				// Remove inclusive tax amount.
				$inclusive_tax_amount = array_reduce(
					$tax_rates,
					function( $amount, $tax_rate ) use ( $unit_amount ) {
						if ( 'exclusive' === $tax_rate->calculation ) {
							return $amount;
						}

						return $amount + ( $unit_amount * ( $tax_rate->percentage / 100 ) );
					},
					0
				);

				$post_inclusive_unit_amount = round( $unit_amount - $inclusive_tax_amount );

				$tax = array_reduce(
					$tax_rates,
					function( $tax, $tax_rate ) use ( $post_inclusive_unit_amount ) {
						if ( 'inclusive' === $tax_rate->calculation ) {
							return $tax;
						}

						$tax_rate = $tax_rate->percentage / 100;

						return $tax + ( $post_inclusive_unit_amount * $tax_rate );
					},
					0
				);

				$unit_amount = round( $unit_amount + $tax );
			}
		}
	}

	$unit_amount = round( $unit_amount );

	// Fee recovery.
	$fee_recovery = 0;

	if (
		function_exists( '\SimplePay\Pro\Payment_Methods\get_form_payment_method_fee_recovery_amount' ) &&
		(
			$form->has_forced_fee_recovery() ||
			isset( $form_values['fee_recovery_toggle'] )
		)
	) {
		$payment_method = sanitize_text_field( $form_values['payment_method_type'] );
		$fee_recovery   = Payment_Methods\get_form_payment_method_fee_recovery_amount(
			$form,
			$payment_method,
			$unit_amount
		);
	}

	return array(
		'amount'       => $unit_amount,
		'currency'     => $currency,
		'fee_recovery' => $fee_recovery,
	);
}
