<?php
/**
 * PaymentIntent trait
 *
 * @package SimplePay
 * @subpackage Core
 * @copyright Copyright (c) 2023, Sandhills Development, LLC
 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
 * @since 4.7.0
 */

namespace SimplePay\Core\RestApi\Internal\Payment\Traits;

use Exception;
use SimplePay\Core\API;
use SimplePay\Core\Payments\Stripe_API;
use SimplePay\Core\RestApi\Internal\Payment\Utils\CouponUtils;
use SimplePay\Core\RestApi\Internal\Payment\Utils\FeeRecoveryUtils;
use SimplePay\Core\RestApi\Internal\Payment\Utils\PaymentRequestUtils;
use SimplePay\Core\RestApi\Internal\Payment\Utils\TaxUtils;

/**
 * PaymentIntentTrait trait.
 *
 * @since 4.7.0
 */
trait PaymentIntentTrait {

	/**
	 * Application fee handling.
	 *
	 * @since 4.7.0
	 *
	 * @var \SimplePay\Core\StripeConnect\ApplicationFee
	 */
	protected $application_fee;

	/**
	 * Creates a PaymentIntent for the given request.
	 *
	 * @since 4.7.0
	 *
	 * @param \WP_REST_Request                  $request The payment request.
	 * @param \SimplePay\Vendor\Stripe\Customer $customer The customer.
	 * @throws \Exception If automatic tax is used and no calculation is available.
	 * @return \SimplePay\Vendor\Stripe\PaymentIntent
	 */
	private function create_payment_intent( $request, $customer ) {
		$form        = PaymentRequestUtils::get_form( $request );
		$form_values = PaymentRequestUtils::get_form_values( $request );
		$price       = PaymentRequestUtils::get_price( $request );
		$customer_id = $customer->id;

		// Start with base arguments that are common to all payment intents,
		// regardless of what generates them (Subscription, Checkout Session, etc).
		$payment_intent_args = array_merge(
			array(
				'metadata' => PaymentRequestUtils::get_payment_intent_metadata( $request ),
				'expand'   => array(
					'customer',
				),
			),
			PaymentRequestUtils::get_payment_intent_data( $request )
		);

		// Set the customer.
		$payment_intent_args['customer'] = $customer_id;

		// Calculate the base amount, which is the unit amount multiplied by the quantity.
		$unit_amount = PaymentRequestUtils::get_amount( $request );

		// Add the application fee, if needed.
		if ( $this->application_fee->has_application_fee() ) {
			$application_fee = $this->application_fee->get_application_fee_amount(
				$unit_amount
			);

			$payment_intent_args['application_fee_amount'] = $application_fee;
		}

		$payment_intent_args['amount']   = $unit_amount;
		$payment_intent_args['currency'] = $price->currency;

		// Add the allowed payment method types.
		$payment_intent_args['payment_method_types'] = PaymentRequestUtils::get_payment_method_types(
			$request
		);

		// Add the payment method options.
		$payment_intent_args['payment_method_options'] = PaymentRequestUtils::get_payment_method_options(
			$request
		);

		/**
		 * Filters arguments used to create a PaymentIntent from a payment form request.
		 *
		 * @since 3.6.0
		 *
		 * @param array<string, mixed>           $payment_intent_args PaymentIntent arguments.
		 * @param \SimplePay\Core\Abstracts\Form $form Form instance.
		 * @param array<mixed>                   $arg2 Deprecated.
		 * @param array<string, mixed>           $form_values Form values.
		 * @param string                         $customer Customer ID.
		 * @return array<string, mixed>
		 */
		$payment_intent_args = apply_filters(
			'simpay_get_paymentintent_args_from_payment_form_request',
			$payment_intent_args,
			$form,
			array(),
			$form_values,
			$customer_id
		);

		/**
		 * Allows processing before a PaymentIntent is created from a payment form request.
		 *
		 * @since 3.6.0
		 *
		 * @param array                          $payment_intent_args Arguments used to create 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 string                         $customer_id Stripe Customer ID.
		 */
		do_action(
			'simpay_before_paymentintent_from_payment_form_request',
			$payment_intent_args,
			$form,
			array(),
			$form_values,
			$customer_id
		);

		// If we are using automatic tax calculations, verify we have a tax
		// calculation we can associate with this payment before creating.
		$tax_status  = get_post_meta( $form->id, '_tax_status', true );
		$tax_calc_id = PaymentRequestUtils::get_tax_calc_id( $request );

		if ( 'automatic' === $tax_status && empty( $tax_calc_id ) ) {
			throw new Exception(
				__( 'Invalid request. Please try again.', 'stripe' )
			);
		}

		$payment_intent = API\PaymentIntents\create(
			$payment_intent_args,
			$form->get_api_request_args()
		);

		// ... and now associate the tax calculation with the payment via a transaction.
		// @link https://stripe.com/docs/api/tax/transactions/create
		if ( 'automatic' === $tax_status ) {
			Stripe_API::request(
				'Tax\Transaction',
				'createFromCalculation',
				array(
					'calculation' => $tax_calc_id,
					'reference'   => $payment_intent->id,
				),
				$form->get_api_request_args()
			);
		}

		/**
		 * Allows further processing after a PaymentIntent is created from a payment form request.
		 *
		 * @since 3.6.0
		 *
		 * @param \SimplePay\Vendor\Stripe\PaymentIntent $paymentintent Stripe 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 string                                 $customer_id Stripe Customer ID.
		 */
		do_action(
			'simpay_after_paymentintent_from_payment_form_request',
			$payment_intent,
			$form,
			array(),
			$form_values,
			$customer_id
		);

		return $payment_intent;
	}

}
