<?php
/**
 * WooCommerce Payments
 *
 * The class is structured to enable WooCommerce Payments to support a range of Adyen payment solutions.
 *
 * @since 1.0.0
 */

namespace WkwcAdyen\Includes\Payment_Methods;

// prevent direct access data leaks
defined( 'ABSPATH' ) || exit;

use WkwcAdyen\Helper\Adyen\Wkwc_Adyen_Helper;

use WkwcAdyen\Helper\Common\Wkwc_Adyen_Checkout_Action;

use WkwcAdyen\Helper\Common\Wkwc_Adyen_Service_Util;

use WkwcAdyen\Helper\Common\Wkwc_Adyen_Order_Handler;

if ( ! class_exists( '\WC_Payment_Gateway' ) ) {
	include_once WP_CONTENT_DIR . '/plugins/woocommerce/includes/abstracts/abstract-wc-settings-api.php';
	include_once WP_CONTENT_DIR . '/plugins/woocommerce/includes/abstracts/abstract-wc-payment-gateway.php';
}


abstract class Wkwc_Adyen_Abstract_Gateway extends \WC_Payment_Gateway {
	/**
	 * Whether or not the payment information was displayed
	 *
	 * @since 1.0.0
	 * @var bool
	 */
	public static $payment_info_displayed = false;

	/**
	 * Whether or not the payment method is active in Adyen account
	 *
	 * @since 1.0.0
	 * @var bool
	 */
	public $is_activated = null;

	/**
	 * List of available currencies.
	 *
	 * @var array
	 */
	public $currencies = array();

	/**
	 * $adyen_config
	 *
	 * @var Wkwc_Adyen_Config
	 */
	public $adyen_config;

	/**
	 * adyen test mode
	 *
	 * @var $test_mode
	 */
	public $test_mode;

	/**
	 * $adyen_helper
	 *
	 * @var Wkwc_Adyen_Helper
	 */
	public $adyen_helper;

	/**
	 * Checkout action instance
	 *
	 * @var Wkwc_Adyen_Checkout_Action
	 */
	public $checkout_action;

	/**
	 * Constructor of this class.
	 *
	 * @param bool $init_hooks
	 * @since 1.0.0
	 */
	public function __construct( $init_hooks = true ) {
		$this->adyen_helper       = new Wkwc_Adyen_Helper();
		$this->adyen_config       = $this->adyen_helper->adyen_config;
		$this->checkout_action    = new Wkwc_Adyen_Checkout_Action();
		$service_util             = new Wkwc_Adyen_Service_Util();
		$this->id                 = strtolower( preg_replace( '/[^A-Za-z0-9\-]/', '_', basename( str_replace( '\\', '/', static::class ) ) ) );
		$this->enabled            = 'no';
		$this->method_title       = $this->get_default_title();
		$this->method_description = $this->get_default_description();
		$this->test_mode          = $this->adyen_config->wkwc_adyen_is_test_mode();
		$this->icon               = $this->get_icon_url();
		$this->title              = $this->get_option( 'title', $this->get_default_title() );
		$this->description        = $this->get_option( 'description' );

		$this->is_activated = $service_util::is_payment_method_active( $this->payment_method_type() );

		$this->supports = array(
			'products',
			'refunds',
		);

		// Load the settings.
		$this->init_form_fields();
		$this->init_settings();

		if ( $init_hooks ) {

			// add_filter( 'woocommerce_wkwc_adyen_amazonpay_update_checkout_session_payload', array( $this, 'wkwc_adyen_update_address_details_for_classic' ), 10, 2 );

			add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );

			add_action( 'woocommerce_thankyou', array( $this, 'received_order_page' ), 1 );
			add_action( 'woocommerce_thankyou', array( $this, 'send_payment_details' ) );
			add_action( 'before_woocommerce_pay', array( $this, 'pay_order_page' ), 1 );

			add_action( 'woocommerce_receipt_' . $this->id, array( $this, 'wkwc_adyen_receipt_page' ) );

			add_action( 'woocommerce_api_wkwc_adyen', array( $this, 'wkwc_adyen_handle_sca_redirect' ) );

			add_action( 'woocommerce_pay_order_after_submit', array( $this, 'display_payment_action' ) );
			add_action( 'woocommerce_after_checkout_form', array( $this, 'display_payment_action' ) );
			add_action( 'woocommerce_thankyou_' . $this->id, array( $this, 'display_payment_action' ) );

		}

	}

	/**
	 * Filter the payload to add the addressDetails data to the checkout session object.
	 *
	 * @param  array    $payload Payload to send to the API before proceeding to checkout.
	 * @param  string   $checkout_session_id Checkout Session Id.
	 * @param  WC_Order $order Order object.
	 * @param  bool     $doing_classic_payment Indicates whether this is an Amazon "Classic" Transaction or not.
	 * @return array
	 */
	public function wkwc_adyen_update_address_details_for_classic( $payload, $order ) {

		$phone_number = $order->get_shipping_phone();
		$phone_number = $phone_number ? $phone_number : $order->get_billing_phone();

		$shipping_state   = $order->get_shipping_state();
		$shipping_country = $order->get_shipping_country( 'edit' );

		$payload['addressDetails'] = array(
			'name'          => rawurlencode( $order->get_shipping_first_name() . ' ' . $order->get_shipping_last_name() ),
			'addressLine1'  => rawurlencode( $order->get_shipping_address_1() ),
			'addressLine2'  => rawurlencode( $order->get_shipping_address_2() ),
			'city'          => rawurlencode( $order->get_shipping_city() ),
			'stateOrRegion' => rawurlencode( $shipping_state ),
			'postalCode'    => rawurlencode( $order->get_shipping_postcode() ),
			'countryCode'   => $shipping_country,
			'phoneNumber'   => rawurlencode( $phone_number ),
		);

		/**
		 * Address Validation for the EU region.
		 *
		 * @see https://developer.amazon.com/docs/amazon-pay-checkout/address-formatting-and-validation.html#address-validation
		 */
		if ( in_array( $payload['addressDetails']['countryCode'], array( 'UK', 'GB', 'SG', 'AE', 'MX' ), true ) ) {
			$payload['addressDetails']['districtOrCounty'] = $payload['addressDetails']['stateOrRegion'];
			unset( $payload['addressDetails']['stateOrRegion'] );
			$payload['addressDetails'] = array_filter( $payload['addressDetails'] );
		}

		return $payload;
	}

	/**
	 * List of countries where the payment method is available only.
	 *
	 * @since 1.1.0
	 * @return array
	 */
	public function available_countries() {

		return array();
	}

	/**
	 * Displays supported countries and currencies.
	 *
	 * @since 1.1.0
	 * @return string
	 */
	public function show_supported_country() {

		$countries = array();

		foreach ( $this->available_countries() as $country_code => $data ) {

			$country_code = '_ANY_' === $country_code ? __( 'ANY', 'wkwc-adyen' ) : $country_code;

			if ( empty( $data['currencies'] ) ) {
				$countries[] = $country_code;
			} else {
				$currencies  = $data['currencies'];
				$countries[] = $country_code . ' (' . implode( ', ', $currencies ) . ')';
			}
		}

		$result = empty( $countries ) ? sprintf( __( '%1$sSupported country:%2$s ANY', 'wkwc-adyen' ), '<b>', '</b>' ) : sprintf( __( '%1$sSupported country:%2$s %3$s', 'wkwc-adyen' ), '<b>', '</b>', implode( ', ', $countries ) );

		return $result;
	}

	/**
	 * Gets default payment method title.
	 *
	 * @since 1.0.0
	 * @return string
	 */
	abstract public function get_default_title();



	/**
	 * Gets default payment method description.
	 *
	 * @since 1.0.0
	 * @return string
	 */
	abstract public function get_default_description();

	 /**
	  * Gets default description set in settings.
	  *
	  * @since 1.0.0
	  * @return string
	  */
	abstract public function get_settings_description();



	/**
	 * Type of the payment method (e.g ideal, scheme. bcmc).
	 *
	 * @since 1.0.0
	 * @return string
	 */
	abstract public function payment_method_type();

	/**
	 * Returns the payment method to be used for recurring payments
	 *
	 * @since 1.0.0
	 * @return string
	 */
	abstract public function recurring_payment_method();

	/**
	 * Gets payment method icon by method type.
	 *
	 * @since 1.0.0
	 * @return string
	 */
	public function get_icon_url() {

		$url = $this->get_option( 'icon_url' );
		$url = empty( $url ) ? WKWC_ADN_PLUGIN_URL . '/assets/front/img/' . $this->payment_method_type() . '.svg' : $url;

		return apply_filters( WKWC_ADN_PREFIX . '_' . $this->id . '_icon_url', $url );
	}



	/**
	 * Checks if the gateway is available for use.
	 *
	 * @since 1.1.1 - check if there is a valid origin key
	 * @since 1.1.0 - check if it's available based on country and currencies
	 * @since 1.0.3 - add currency verification
	 * @since 1.0.0
	 * @return bool
	 */
	public function is_available() {

		if ( empty( $this->adyen_config->wkwc_adyen_get_origin_key() ) ) {
			return false;
		}

		// only in WooCommerce checkout
		if ( WC()->cart && $this->get_order_total() > 0 ) {

			if ( ! empty( $this->available_countries() ) ) {

				$available_country = $this->available_countries();

				$customer_country = WC()->customer->get_billing_country();
				$any_country      = isset( $available_country['_ANY_'] ) ? $available_country['_ANY_'] : '';
				$country          = isset( $available_country[ $customer_country ] ) ? $available_country[ $customer_country ] : array();

				if ( empty( $country ) && empty( $any_country ) ) {

					return false;

				} else {

					$currencies = empty( $any_country ) ? $country['currencies'] : $any_country['currencies'];

					if ( ! empty( $currencies ) && ! in_array( get_woocommerce_currency(), $currencies ) ) {

						return false;
					}
				}
			}
		}

		return parent::is_available();
	}

	/**
	 * Return whether or not this gateway still requires setup to function.
	 *
	 * When this gateway is toggled on via AJAX, if this returns true a
	 * redirect will occur to the settings page instead.
	 *
	 * @since 1.0.0
	 * @return bool
	 */
	public function needs_setup() {

		if ( ! $this->is_activated ) {
			return true;
		}

		return false;
	}

	/**
	 * Gets the transaction URL.
	 *
	 * @since 1.0.0
	 * @param  WC_Order $order Order object.
	 * @return string
	 */
	public function get_transaction_url( $order ) {

		$this->view_transaction_url = $this->get_service_base_url() . '/ca/ca/accounts/showTx.shtml?txType=Payment&pspReference=%s&accountKey=MerchantAccount.' . $this->adyen_config->wkwc_adyen_get_merchantcode();

		return parent::get_transaction_url( $order );
	}

	/**
	 * Gets the base URL of Adyen platform
	 *
	 * @since 1.0.0
	 * @return string
	 */
	public function get_service_base_url() {

		if ( $this->test_mode ) {
			return 'https://ca-test.adyen.com';
		}

		return 'https://ca-live.adyen.com';
	}

	/**
	 * Gets details of a given method type.
	 *
	 * @since 1.0.0
	 * @return array
	 */
	public function get_payment_method_details() {

		$method = array();

		foreach ( $this->checkout_action->wkwc_adyen_get_payment_methods() as $method ) {
			if ( $method['type'] == $this->payment_method_type() ) {
				return $method;
			}
		}

		return $method;

	}


	/**
	 * Checks if a given payment method is enabled in WooCommerce
	 *
	 * @since 1.0.0
	 * @param string $method_id
	 * @return boolean
	 */
	public function is_payment_method_enabled( $method_id ) {

		$method_settings = get_option( "woocommerce_{$method_id}_settings", array() );

		if ( $method_settings['enabled'] === 'yes' ) {
			return true;
		}

		return false;
	}

	/**
	 * Checks whether or not SEPA Direct Debit is enabled then this could support recurring payments
	 *
	 * @since 1.0.0
	 * @return bool
	 */
	public function support_recurring() {

		if ( $this->is_payment_method_enabled( 'wkwc_adyen_sepa_direct_debit' ) ) {
			return true;
		}

		return false;
	}

	/**
	 * Validates extra added fields.
	 *
	 * @since 1.0.0
	 * @return bool
	 */
	public function validate_fields() {
		return parent::validate_fields();
	}

	 /**
	  * Processes the payment.
	  *
	  * @param int $order_id
	  * @return array
	  */
	public function process_payment( $order_id ) {
		$order = wc_get_order( $order_id );
		$order->update_meta_data( '_' . WKWC_ADN_PREFIX . '_shopper_reference', $this->adyen_helper->get_shopper_reference() );
		$order->update_meta_data( 'wkwc_adyen_mode', 'authorize_payment' );
		$order->save();
	}

	/**
	 * Processes a refund.
	 *
	 * @since 1.1.0 - show error if payment reference is empty
	 * @since 1.0.0
	 * @param  int    $order_id Order ID.
	 * @param  float  $amount Refund amount.
	 * @param  string $reason Refund reason.
	 * @return boolean True or false based on success, or a WP_Error object.
	 */
	public function process_refund( $order_id, $amount = null, $reason = '' ) {
		$response         = null;
		$order            = wc_get_order( $order_id );
		$reference        = $order->get_meta( '_' . WKWC_ADN_PREFIX . '_payment_pspReference' );
		$payment_captured = $order->get_meta( '_' . WKWC_ADN_PREFIX . '_payment_captured' );

		if ( empty( $reference ) ) {
			return new \WP_Error( 'broke', __( 'Sorry you cannot refund this because the payment reference is invalid. Please try to refund it manually from Adyen account.', 'wkwc-adyen' ) );
		}

		if ( $payment_captured === 'yes' ) {

			$response = $this->checkout_action->refund_payment( $reference, $amount );

			wkwc_adn_log( 'Refund Order response data: ' . print_r( $response, true ) );

		} else {

			if ( $amount == $order->get_total() ) {

				$response = $this->checkout_action->cancel_payment( $reference );
				wkwc_adn_log( 'Refund Order response data: ' . print_r( $response, true ) );
			} else {

				return new \WP_Error(
					'broke',
					__( 'Sorry, you cannot refund a partial amount because the transaction has not been captured yet but only cancel the entire payment', 'wkwc-adyen' )
				);
			}
		}

		if ( $response !== null && $response->status == 201 ) {
			$body_response = $this->adyen_helper::wkwc_adyen_obj_to_arr( $response->body );
			$order->read_meta_data();
			$order_psp_reference = $order->get_meta( '_' . WKWC_ADN_PREFIX . '_payment_pspReference' );

			if ( $order_psp_reference !== $body_response['pspReference'] ) {

				$order->update_meta_data( '_' . WKWC_ADN_PREFIX . '_refund_pspReference', $body_response['pspReference'] );

			}

			return true;

		} else {

			$order->add_order_note( sprintf( __( 'The refund did not succeed. Request response: %s', 'wkwc-adyen' ), json_encode( $body_response ) ) );

		}

		$order->save();

		return false;
	}

	/**
	 * Adds an array of fields to be displayed on the gateway's settings screen.
	 *
	 * @since 1.0.7 - use `get_settings_description` instead of `get_default_description`
	 * @since 1.0.0
	 * @return void
	 */
	public function init_form_fields() {

		if ( ! $this->is_activated ) {

			$this->form_fields = array(
				'show_notice' => array(
					'type' => 'show_notice',
				),
			);

		} else {

			$this->form_fields = array(
				'enabled'     => array(
					'title'   => __( 'Enable/Disable', 'wkwc-adyen' ),
					'type'    => 'checkbox',
					'label'   => sprintf( __( 'Enable %s', 'wkwc-adyen' ), $this->get_default_title() ),
					'default' => 'no',
				),
				'title'       => array(
					'title'    => __( 'Title', 'wkwc-adyen' ),
					'type'     => 'text',
					'desc_tip' => __( 'The title which the user sees during checkout.', 'wkwc-adyen' ),
					'default'  => $this->get_default_title(),
				),
				'description' => array(
					'title'    => __( 'Description', 'wkwc-adyen' ),
					'type'     => 'text',
					'desc_tip' => __( 'The description which the user sees during checkout.', 'wkwc-adyen' ),
					'default'  => $this->get_settings_description(),
					'required' => true,
				),
				'icon_url'    => array(
					'title'    => __( 'Icon URL', 'wkwc-adyen' ),
					'type'     => 'url',
					'desc_tip' => __( 'The URL of the payment icon. Leave empty to use the default.', 'wkwc-adyen' ),
				),
			);
		}
	}

	/**
	 * Generates the HTML for `show_notice` field type
	 *
	 * @since 1.0.0
	 * @return string
	 */
	public function generate_show_notice_html() {

		ob_start();
		?>
	  <tr valign="top">
			<td colspan="2" class="forminp" style="padding: 0;">
				<p>
				<?php
				printf(
					__( 'This payment method is not enabled in your Adyen account. %1$sGo to my account.%2$s', 'integration-adyen-woocommerce' ),
					'<a href="' . $this->get_service_base_url() . '" target="_blank">',
					'</a>'
				);
				?>
				</p>
			</td>
		</tr>
		<?php

		return ob_get_clean();
	}

	/**
	 * Unset keys json box.
	 *
	 * @return bool|void
	 */
	public function process_admin_options() {
		if ( check_admin_referer( 'woocommerce-settings' ) ) {
			if ( isset( $_FILES['woocommerce_wkwc_adyen_amazonpay_private_key_file'] ) && isset( $_FILES['woocommerce_wkwc_adyen_amazonpay_private_key_file']['size'] ) && 0 < $_FILES['woocommerce_wkwc_adyen_amazonpay_private_key_file']['size'] ) {
				// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.ValidatedSanitizedInput.MissingUnslash
				$pem_file = $_FILES['woocommerce_wkwc_adyen_amazonpay_private_key_file'];

				$finfo = new \finfo( FILEINFO_MIME_TYPE );
				$ext   = $finfo->file( $pem_file['tmp_name'] );
				if ( 'text/plain' === $ext && isset( $pem_file['tmp_name'] ) ) {
					// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
					$private_key = file_get_contents( $pem_file['tmp_name'] );
					$this->save_private_key( $private_key );
				}
			}
			parent::process_admin_options();
		}
	}

	/**
	 * Save private key.
	 *
	 * @param string $private_key Private key PEM string.
	 */
	protected function save_private_key( $private_key ) {
		$validate_private_key = openssl_pkey_get_private( $private_key );
		if ( $validate_private_key ) {
			update_option( 'woocommerce_wkwc_adyen_amazon_payments_advanced_private_key', $private_key );
			return true;
		}

		return false;
	}

	/**
	 * Displays payment information on thank you page.
	 *
	 * @since 1.2.0 - change function name
	 * @since 1.0.0
	 * @param int $order_id
	 * @return string|void
	 */
	public function received_order_page( $order_id ) {

		$order = wc_get_order( $order_id );
		$info  = sprintf( __( 'Order completed using %s', 'wkwc-adyen' ), $order->get_payment_method_title() );

		if ( ! self::$payment_info_displayed && $order->get_payment_method() === $this->id ) {
			echo '<section class="woocommerce-info" >' . wptexturize( esc_html( $info ) ) . '</section>';

			self::$payment_info_displayed = true;
		}

		// collect payload if any
		if ( isset( $_GET['payload'] ) ) {
			$order->update_meta_data( '_' . WKWC_ADN_PREFIX . '_payment_payload', $_GET ['payload'] );
			$order->save();
		}

		// collect redirect result if any
		if ( isset( $_GET['redirectResult'] ) ) {
			$order->update_meta_data( '_' . WKWC_ADN_PREFIX . '_payment_redirectResult', $_GET ['redirectResult'] );
			$order->save();
		}
	}

	 /**
	  * Displays payment information on pay order page.
	  *
	  * @return string|void
	  */
	public function pay_order_page() {

		$order_id = wc_get_order_id_by_order_key( $_GET['key'] );
		$order    = wc_get_order( $order_id );

		if ( $order instanceof \WC_Order ) {

			if ( ! self::$payment_info_displayed && $order->get_payment_method() === $this->id && isset( $_GET['payment_result'] ) && 'failed' === $_GET['payment_result'] ) {

				$info = __( 'Your payment was not successful. Please complete your order with a different payment method.', 'wkwc-adyen' );

				echo '<section class="woocommerce-info" >' . wptexturize( esc_html( $info ) ) . '</section>';

				self::$payment_info_displayed = true;
			}
		}
	}

	/**
	 * Receipt Page.
	 *
	 * @param int $order_id Order Id.
	 *
	 * @return mixed
	 */
	public function wkwc_adyen_receipt_page( $order_id ) {
		$action = get_option( 'wkwc_adyen_redirect_object_' . $order_id );
		if ( ! isset( $action['url'] ) ) {
			return;
		}

		$endpoint   = add_query_arg( 'wc-api', 'wkwc_adyen_redirect', trailingslashit( get_home_url() ) );
		$return_url = add_query_arg( 'order_id', $order_id, $endpoint );

		echo '<form action="' . esc_url( $action['url'] ) . '" method="post" id="wkwc_adyen_payment_form">';
		foreach ( $action['data'] as $key => $value ) {
			if ( 'TermUrl' === $key ) {
				$value = $return_url;
			}
			echo '<input type="hidden" name="' . esc_attr( $key ) . '" value="' . esc_attr( $value ) . '" />';
		}
		echo '</form>';
		echo '<script>jQuery(document).ready(function(){
			jQuery("#wkwc_adyen_payment_form").submit();
		});</script>';
	}

	/**
	 * Handle Redirect
	 *
	 * @return void
	 */
	public function wkwc_adyen_handle_sca_redirect() {

		$request_data = isset( $_REQUEST ) ? wc_clean( $_REQUEST ) : array();
		wkwc_adn_log( "Adyen Payment Details: $order_id: " . print_r( $request_data, true ) );
		$redirect_action_data = ! empty( $request_data ) && isset( $request_data['action'] ) ? $request_data['action'] : array();

		$redirect_data = ! empty( $redirect_action_data ) && isset( $redirect_action_data['data'] ) ? $redirect_action_data['data'] : array();

		$order_id = isset( $request_data['order_id'] ) ? intval( $request_data['order_id'] ) : 0;

		$order = wc_get_order( $order_id );
		if ( ! $order_id ) {
			wp_safe_redirect( wc_get_checkout_url() );
			exit;
		} elseif ( ! isset( $redirect_data['MD'] ) ) {
			wp_die( 'error: MD' ); // todo don't die here.
		} elseif ( ! isset( $redirect_data['PaRes'] ) ) {
			wp_safe_redirect( $this->get_return_url( $order ) );
			exit;
		}

		$md     = $redirect_data['MD'];
		$pa_res = $redirect_data['PaRes'];

		$action = get_option( 'wkwc_adyen_redirect_object_' . $order_id );

		if ( ! $action ) {
			wp_safe_redirect( $this->get_return_url( $order ) );
			exit;
		}

		wkwc_adn_log( "Adyen Payment Details: $order_id: " . print_r( $request_data, true ) );

		delete_option( 'wkwc_adyen_redirect_object' );

		$payment_details = $this->adyen_helper->wkwc_adyen_get_payment_details( $md, $pa_res, $action['paymentData'] );

		if ( ! isset( $payment_details['resultCode'] ) ) {
			wp_safe_redirect( $this->get_return_url( $order ) );
			exit;
		}

		// Payment went through.
		$order->update_meta_data( '_woocommerce_adyen_payment_data', $payment_details );
		$order->payment_complete();
		/* translators: %s: is Transaction reference */
		$order->add_order_note( sprintf( __( 'Payment was complete via Adyen (PSP Reference: %s)', 'wkwc-adyen' ), $adyen->wkwc_adyen_get_adyen_transaction_url( $payment_details['pspReference'] ) ) );

		wp_safe_redirect( $this->get_return_url( $order ) );
		exit;
	}

	 /**
	  * Create a list with the order items which will be used in API request
	  *
	  * @since 1.1.0
	  * @param \WC_Order $order
	  * @return void
	  */
	public function list_order_items( \WC_Order $order ) {

		$list_items = array();

		foreach ( $order->get_items() as $item ) {

			$tax_percentage = 0;
			$price_excl_tax = floatval( $item->get_total() );
			$tax_amount     = $item->get_total_tax();
			$product        = $item->get_product();
			$price_incl_tax = $price_excl_tax + $tax_amount;

			if ( is_float( $price_excl_tax ) && $price_excl_tax > 0 ) {
				$tax_percentage = $tax_amount * 100 / $price_excl_tax;
			}

			$list_items[] = array(
				'id'                 => $product->get_id(),
				'quantity'           => $item->get_quantity(),
				'amountIncludingTax' => $this->adyen_helper->wkwc_adyen_format_amount( $price_incl_tax ),
				'amountExcludingTax' => $this->adyen_helper->wkwc_adyen_format_amount( $price_excl_tax ),
				'taxAmount'          => $this->adyen_helper->wkwc_adyen_format_amount( $tax_amount ),
				'taxPercentage'      => $this->adyen_helper->wkwc_adyen_format_amount( $tax_percentage ),
				'description'        => $product->get_name(),
				'productUrl'         => get_permalink( $product->get_id() ),
				'imageUrl'           => wp_get_attachment_url( $product->get_image_id() ),
			);
		}

		return $list_items;
	}

	/**
	 * Builds the required payment payload
	 *
	 * @param \WC_Order $order
	 * @param string    $reference
	 * @return array
	 */
	public function build_payment_payload( \WC_Order $order, $reference ) {
		$shipping        = $order->get_shipping_methods();
		$name            = $order->get_billing_first_name() . ' ' . $order->get_billing_last_name();
		$billing_address = array(
			'street'            => $order->get_billing_address_1(),
			'postalCode'        => $order->get_billing_postcode(),
			'city'              => $order->get_billing_city(),
			'houseNumberOrName' => $name,
			'stateOrProvince'   => $order->get_billing_state(),
			'country'           => $order->get_billing_country(),
		);

		if ( empty( $shipping ) ) {
			$shipping_address = $billing_address;
		} else {
			$shipping_address = array(
				'postalCode'        => $order->get_shipping_postcode(),
				'city'              => $order->get_shipping_city(),
				'houseNumberOrName' => $name,
				'street'            => $order->get_shipping_address_1(),
				'stateOrProvince'   => $order->get_shipping_state(),
				'country'           => $order->get_shipping_country(),
			);
		}
		$payload = apply_filters(
			'wkwc_adyen_payment_pre_payload_data',
			array(
				'channel'                  => 'web',
				'origin'                   => home_url(),
				'reference'                => self::add_reference_prefix( $reference ),
				'returnUrl'                => $this->get_return_url( $order ),
				'merchantAccount'          => $this->adyen_config->wkwc_adyen_get_merchantcode(),
				'countryCode'              => $order->get_billing_country(),
				'telephoneNumber'          => $order->get_billing_phone(),
				'lineItems'                => $this->list_order_items( $order ),
				'recurringProcessingModel' => self::has_subscription() ? 'Subscription' : 'CardOnFile',
				'shopperInteraction'       => 'Ecommerce',
				'shopperIP'                => $this->adyen_helper->wkwc_adyen_get_client_ip(),
				'shopperLocale'            => $this->adyen_helper->wkwc_adyen_get_locale(),
				'shopperEmail'             => $order->get_billing_email(),
				'shopperReference'         => $order->get_meta( '_' . WKWC_ADN_PREFIX . '_shopper_reference', true ),
				'shopperName'              => array(
					'firstName' => $order->get_billing_first_name(),
					'lastName'  => $order->get_billing_last_name(),
				),
				'amount'                   => array(
					'currency' => get_woocommerce_currency(),
					'value'    => $this->adyen_helper->wkwc_adyen_format_amount( $this->get_order_total() ),
				),
				'paymentMethod'            => array(
					'type' => $this->payment_method_type(),
				),
				'billingAddress'           => $billing_address,
				'deliveryAddress'          => $shipping_address,
				'browserInfo'              => array(
					'userAgent'      => $_SERVER['HTTP_USER_AGENT'],
					'acceptHeader'   => $_SERVER['HTTP_ACCEPT'],
					'language'       => $this->adyen_helper->wkwc_adyen_get_locale(),
					'javaEnabled'    => true,
					'colorDepth'     => 24,
					'timeZoneOffset' => 0,
					'screenHeight'   => 723,
					'screenWidth'    => 1536,
				),
			)
		);

		$store = $this->adyen_helper->wkwc_adyen_get_store( $order );

		if ( ! empty( $store ) ) {

			$payload['store'] = $store;

		}

		return $payload;
	}

	/**
	 * Adds the prefix to the given reference.
	 *
	 * @since 1.1.0
	 * @param string $reference
	 * @return string
	 */
	public static function add_reference_prefix( $reference ) {

		$prefix = get_option( 'wkwc_adyen_order_reference_prefix' );
		$prefix = empty( $prefix ) ? '' : "{$prefix}-";

		return $prefix . $reference;

	}

	/**
	 * Checks if checkout contains at least one subscription.
	 *
	 * @since 1.0.9 - added support for variable subscription
	 *              - change name to `has_subscription`
	 * @since 1.0.3
	 * @return bool
	 */
	public static function has_subscription() {

		if ( WC()->cart ) {

			foreach ( WC()->cart->get_cart() as $item ) {
				if ( $item['data']->is_type( array( 'subscription_variation', 'subscription' ) ) ) {
					return true;
				}
			}
		}

		return false;
	}

	 /**
	  * Sends received payment details to be processed
	  *
	  * @since 1.1.3 - add support for API Checkout v67
	  * @since 1.0.0
	  * @return void
	  */
	public function send_payment_details() {

		if ( is_checkout() && isset( $_GET['key'] ) && ( isset( $_GET['redirectResult'] ) || isset( $_GET['payload'] ) ) ) {

			$order_id = wc_get_order_id_by_order_key( $_GET['key'] );
			$order    = wc_get_order( $order_id );

			if ( $order instanceof \WC_Order ) {
				wkwc_adn_log( "Adyen Google pay thankyou page send payment detail for order id: $order_id: ". $order->get_payment_method() . 'Using payment method : '.$this->id  );
				// only if matches the our payment methods
				if ( $order->get_payment_method() === $this->id ) {

					if ( isset( $_GET['redirectResult'] ) ) {

						$payload = array(
							'details' => array(
								'redirectResult' => urldecode( $_GET['redirectResult'] ),
							),
						);

						$response = $this->checkout_action->send_payment_details( $payload );

						Wkwc_Adyen_Order_Handler::payment_result( $order, $response );

						/**
						 * this is a temporary fix for payment methods like PayPal
					  *
						 * @since 1.3.2 - simulate the request response
						 * @since 1.2.0
						 */
					} elseif ( isset( $_GET['payload'] ) && isset( $_GET['resultCode'] ) ) {
						Wkwc_Adyen_Order_Handler::payment_result(
							$order,
							(object) array(
								'status' => 200,
								'body'   => (object) array(
									'resultCode' => $_GET['resultCode'],
								),
							)
						);
					}
				}
			}
		}

	}


	/**
	 * Displays the payment action in a popup.
	 *
	 * @since 1.3.0
	 * @return string
	 */
	public function display_payment_action() {

		if ( isset( $_GET[ WKWC_ADN_PREFIX . '_payment_method' ] ) ) {

			$order_id = get_query_var( 'order-pay', get_query_var( 'order-received', $_GET['wkwc_adyen_order_id'] ) );
			$order    = wc_get_order( $order_id );

			if ( ! $order instanceof \WC_Order ) {
				return;
			}

			$payment_method = $_GET[ WKWC_ADN_PREFIX . '_payment_method' ];
			$payment_action = $order->get_meta( '_' . WKWC_ADN_PREFIX . '_payment_action' );

			if ( ! empty( $payment_action ) && $payment_method == $this->payment_method_type() ) {

				$payment_action = json_encode( $payment_action );

				?>
			<div class="wkwc-adyen-popup" style="display: none;">
			   <div>
				  <div id="wkwc-adyen-payment-action-data" class="wkwc-adyen-component" data-payment_action='<?php echo esc_attr( $payment_action ); ?>' data-order_id="<?php echo esc_attr( $order_id ); ?>">
					 <div class="wkwc-adyen-component__text"><?php _e( 'Processing...', 'wkwc-adyen' ); ?></div>
				  </div>
			   </div>
			</div>
				<?php
			}
		}
	}



	/**
	 * Get the payment action for order
	 *
	 * @return array|mixed|string
	 */
	public function get_payment_action() {
		global $wp_query;

		if ( isset( $_GET[ WKWC_ADN_PREFIX . '_payment_method' ] ) ) {

			$order_id = get_query_var( 'order-pay', get_query_var( 'order-received', $_GET['wkwc_adyen_order_id'] ) );
			$order    = wc_get_order( $order_id );

			if ( ! $order instanceof \WC_Order ) {
				return array();
			}

			$payment_method = $_GET[ WKWC_ADN_PREFIX . '_payment_method' ];
			$payment_action = $order->get_meta( '_' . WKWC_ADN_PREFIX . '_payment_action' );

			if ( ! empty( $payment_action ) && $payment_method == $this->payment_method_type() ) {

				return $payment_action;

			}
		}

		return array();

	}



	/**
	 * Get the shopper locale
	 *
	 * @return string
	 */
	protected function get_locale() {
		return str_replace( array( '_informal', '_formal' ), '', get_locale() );
	}
}
